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 2023/03/09 07:27:26 UTC

[iotdb] branch master updated: [IOTDB-5630] Make Function cast a built-in function

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 8ef861bc6b [IOTDB-5630] Make Function cast a built-in function
8ef861bc6b is described below

commit 8ef861bc6bc0191683699b4565a9606e27fb4932
Author: Liao Lanyu <14...@qq.com>
AuthorDate: Thu Mar 9 15:27:19 2023 +0800

    [IOTDB-5630] Make Function cast a built-in function
---
 .../org/apache/iotdb/db/qp/sql/IdentifierParser.g4 |    1 +
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |    1 +
 .../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4  |    4 +
 docs/UserGuide/Operators-Functions/Conversion.md   |  151 ++-
 .../zh/UserGuide/Operators-Functions/Conversion.md |  155 ++-
 .../iotdb/db/query/udf/example/ConstValue.java     |   42 +
 .../itbase/constant/BuiltinScalarFunctionEnum.java |   21 +-
 .../BuiltinTimeSeriesGeneratingFunctionEnum.java   |    1 -
 .../it/IoTDBSyntaxConventionStringLiteralIT.java   |    7 +-
 .../scalar/IoTDBCastFunctionIT.java                | 1032 ++++++++++++++++++++
 .../iotdb/db/it/udf/IoTDBUDFManagementIT.java      |   14 +-
 ....java => IoTDBUDTFBuiltinScalarFunctionIT.java} |    2 +-
 .../iotdb/session/it/IoTDBSessionSimpleIT.java     |   12 +-
 .../apache/iotdb/commons/conf/IoTDBConstant.java   |    1 +
 ...tinFunction.java => BuiltinScalarFunction.java} |   20 +-
 .../BuiltinTimeSeriesGeneratingFunction.java       |    1 -
 .../apache/iotdb/commons/udf/builtin/UDTFCast.java |  253 -----
 .../org/apache/iotdb/db/constant/SqlConstant.java  |    3 +
 .../db/mpp/plan/analyze/ExpressionAnalyzer.java    |    8 +-
 .../mpp/plan/analyze/ExpressionTypeAnalyzer.java   |    7 +-
 .../config/metadata/ShowFunctionsTask.java         |   15 +
 .../plan/expression/multi/FunctionExpression.java  |   52 +-
 .../db/mpp/plan/expression/multi/FunctionType.java |    2 +-
 .../BuiltInFunctionHelper.java}                    |    9 +-
 .../multi/builtin/BuiltInScalarFunctionHelper.java |   74 ++
 .../BuiltInScalarFunctionHelperFactory.java}       |   23 +-
 .../multi/builtin/helper/CastHelper.java           |  148 +++
 .../multi/builtin/helper/DiffHelper.java           |   77 ++
 .../visitor/ColumnTransformerVisitor.java          |   23 +-
 .../visitor/IntermediateLayerVisitor.java          |   22 +-
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       |   38 +-
 .../scalar/CastFunctionColumnTransformer.java      |  230 +++++
 .../DiffFunctionColumnTransformer.java             |    3 +-
 .../unary/scalar/CastFunctionTransformer.java      |  228 +++++
 .../{ => scalar}/DiffFunctionTransformer.java      |    3 +-
 .../apache/iotdb/db/utils/TypeInferenceUtils.java  |   43 +-
 36 files changed, 2135 insertions(+), 591 deletions(-)

diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
index 11450e868c..06eb8d3d71 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4
@@ -49,6 +49,7 @@ keyWords
     | BOUNDARY
     | BY
     | CACHE
+    | CAST
     | CHILD
     | CLEAR
     | CLUSTER
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index d805cb9b9a..a2266b9f05 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -960,6 +960,7 @@ expression
     | constant
     | time=(TIME | TIMESTAMP)
     | fullPathInExpression
+    | CAST LR_BRACKET castInput=expression AS attributeValue RR_BRACKET
     | functionName LR_BRACKET expression (COMMA expression)* RR_BRACKET
     | (PLUS | MINUS | OPERATOR_NOT) expressionAfterUnaryOperator=expression
     | leftExpression=expression (STAR | DIV | MOD) rightExpression=expression
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index cdfcea1ad3..7fb68b8710 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -109,6 +109,10 @@ CACHE
     : C A C H E
     ;
 
+CAST
+    : C A S T
+    ;
+
 CHILD
     : C H I L D
     ;
diff --git a/docs/UserGuide/Operators-Functions/Conversion.md b/docs/UserGuide/Operators-Functions/Conversion.md
index e70dd634ce..ed8c47d376 100644
--- a/docs/UserGuide/Operators-Functions/Conversion.md
+++ b/docs/UserGuide/Operators-Functions/Conversion.md
@@ -21,107 +21,82 @@
 
 # Data Type Conversion Function
 
-The IoTDB currently supports 6 data types, including INT32, INT64 ,FLOAT, DOUBLE, BOOLEAN, TEXT. When we query or evaluate data, we may need to convert data types, such as TEXT to INT32, or improve the accuracy of the data, such as FLOAT to DOUBLE. Therefore, IoTDB supports the use of cast functions to convert data types.
+The IoTDB currently supports 6 data types, including INT32, INT64 ,FLOAT, DOUBLE, BOOLEAN, TEXT. When we query or evaluate data, we may need to convert data types, such as TEXT to INT32, or FLOAT to DOUBLE. IoTDB supports cast function to convert data types.
 
-| Function Name | Required Attributes                                          | Output Series Data Type                      | Series Data Type  Description                               |
-| ------------- | ------------------------------------------------------------ | -------------------------------------------- | ----------------------------------------------------------- |
-| CAST          | `type`: the type of the output data point, it can only be INT32 / INT64 / FLOAT / DOUBLE / BOOLEAN / TEXT | Determined by the required attribute  `type` | Converts data to the type specified by the `type` argument. |
+Syntax example:
 
-#### Notes
-1. The value of type BOOLEAN is `true`, when data is converted to BOOLEAN if INT32 and INT64 are not 0, FLOAT and DOUBLE are not 0.0, TEXT is not empty string or "false", otherwise `false`.    
+```sql
+SELECT cast(s1 as INT32)from root.sg
+```
+
+The syntax of the cast function is consistent with that of PostgreSQL. The data type specified after AS indicates the target type to be converted. Currently, all six data types supported by IoTDB can be used in the cast function. The conversion rules to be followed are shown in the following table. The row represents the original data type, and the column represents the target data type to be converted into:
+
+|             | **INT32**                                                    | **INT64**                                                    | **FLOAT**                                                    | **DOUBLE**              | **BOOLEAN**                                                  | **TEXT**                         |
+| ----------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------------------- | ------------------------------------------------------------ | -------------------------------- |
+| **INT32**   | No need to cast                                              | Cast directly                                                | Cast directly                                                | Cast directly           | !=0 : true<br />==0: false                                   | String.valueOf()                 |
+| **INT64**   | Out of the range of INT32: throw Exception<br />Otherwise: Cast directly | No need to cast                                              | Cast directly                                                | Cast directly           | !=0L : true<br />==0: false                                  | String.valueOf()                 |
+| **FLOAT**   | Out of the range of INT32: throw Exception<br />Otherwise: Math.round() | Out of the range of INT64: throw Exception<br />Otherwise: Math.round() | No need to cast                                              | Cast directly           | !=0.0f : true<br />==0: false                                | String.valueOf()                 |
+| **DOUBLE**  | Out of the range of INT32: throw Exception<br />Otherwise: Math.round() | Out of the range of INT64: throw Exception<br />Otherwise: Math.round() | Out of the range of FLOAT:throw Exception<br />Otherwise: Cast directly | No need to cast         | !=0.0 : true<br />==0: false                                 | String.valueOf()                 |
+| **BOOLEAN** | true: 1<br />false: 0                                        | true: 1L<br />false: 0                                       | true: 1.0f<br />false: 0                                     | true: 1.0<br />false: 0 | No need to cast                                              | true: "true"<br />false: "false" |
+| **TEXT**    | Integer.parseInt()                                           | Long.parseLong()                                             | Float.parseFloat()                                           | Double.parseDouble()    | text.toLowerCase =="true" : true<br />text.toLowerCase =="false" : false<br />Otherwise: throw Exception | No need to cast                  |
+
+#### Examples
 
 ```
-IoTDB> show timeseries root.sg.d1.*;
-+-------------+-----+-------------+--------+--------+-----------+----+----------+
-|   timeseries|alias|     database|dataType|encoding|compression|tags|attributes|
-+-------------+-----+-------------+--------+--------+-----------+----+----------+
-|root.sg.d1.s3| null|      root.sg|   FLOAT|     RLE|     SNAPPY|null|      null|
-|root.sg.d1.s4| null|      root.sg|  DOUBLE|     RLE|     SNAPPY|null|      null|
-|root.sg.d1.s5| null|      root.sg|    TEXT|   PLAIN|     SNAPPY|null|      null|
-|root.sg.d1.s6| null|      root.sg| BOOLEAN|     RLE|     SNAPPY|null|      null|
-|root.sg.d1.s1| null|      root.sg|   INT32|     RLE|     SNAPPY|null|      null|
-|root.sg.d1.s2| null|      root.sg|   INT64|     RLE|     SNAPPY|null|      null|
-+-------------+-----+-------------+--------+--------+-----------+----+----------+
-Total line number = 6
-It costs 0.006s
+// timeseries
+IoTDB> show timeseries root.sg.d1.**
++-------------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+
+|   Timeseries|Alias|Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|
++-------------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+
+|root.sg.d1.s3| null| root.sg|   FLOAT|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s4| null| root.sg|  DOUBLE|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s5| null| root.sg| BOOLEAN|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s6| null| root.sg|    TEXT|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s1| null| root.sg|   INT32|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s2| null| root.sg|   INT64|   PLAIN|     SNAPPY|null|      null|    null|              null|
++-------------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+
+
+// data of timeseries
 IoTDB> select * from root.sg.d1;
 +-----------------------------+-------------+-------------+-------------+-------------+-------------+-------------+
 |                         Time|root.sg.d1.s3|root.sg.d1.s4|root.sg.d1.s5|root.sg.d1.s6|root.sg.d1.s1|root.sg.d1.s2|
 +-----------------------------+-------------+-------------+-------------+-------------+-------------+-------------+
-|1970-01-01T08:00:00.001+08:00|          1.1|          1.1|         test|        false|            1|            1|
-|1970-01-01T08:00:00.002+08:00|         -2.2|         -2.2|        false|         true|           -2|           -2|
-|1970-01-01T08:00:00.003+08:00|          0.0|          0.0|         true|         true|            0|            0|
+|1970-01-01T08:00:00.000+08:00|          0.0|          0.0|        false|        10000|            0|            0|
+|1970-01-01T08:00:00.001+08:00|          1.0|          1.0|        false|            3|            1|            1|
+|1970-01-01T08:00:00.002+08:00|          2.7|          2.7|         true|         TRue|            2|            2|
+|1970-01-01T08:00:00.003+08:00|         3.33|         3.33|         true|        faLse|            3|            3|
 +-----------------------------+-------------+-------------+-------------+-------------+-------------+-------------+
-Total line number = 3
-It costs 0.009s
-IoTDB> select cast(s1, 'type'='BOOLEAN'), cast(s2, 'type'='BOOLEAN'), cast(s3, 'type'='BOOLEAN'), cast(s4, 'type'='BOOLEAN'), cast(s5, 'type'='BOOLEAN') from root.sg.d1;
-+-----------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+
-|                         Time|cast(root.sg.d1.s1, "type"="BOOLEAN")|cast(root.sg.d1.s2, "type"="BOOLEAN")|cast(root.sg.d1.s3, "type"="BOOLEAN")|cast(root.sg.d1.s4, "type"="BOOLEAN")|cast(root.sg.d1.s5, "type"="BOOLEAN")|
-+-----------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+
-|1970-01-01T08:00:00.001+08:00|                                 true|                                 true|                                 true|                                 true|                                 true|
-|1970-01-01T08:00:00.002+08:00|                                 true|                                 true|                                 true|                                 true|                                false|
-|1970-01-01T08:00:00.003+08:00|                                false|                                false|                                false|                                false|                                 true|
-+-----------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+
-Total line number = 3
-It costs 0.012s
-```
 
-2. The value of type INT32, INT64, FLOAT, DOUBLE are 1 or 1.0 and TEXT is "true", when BOOLEAN data is true, otherwise 0, 0.0 or "false".  
-
-```
-IoTDB> select cast(s6, 'type'='INT32'), cast(s6, 'type'='INT64'), cast(s6, 'type'='FLOAT'), cast(s6, 'type'='DOUBLE'), cast(s6, 'type'='TEXT') from root.sg.d1;
-+-----------------------------+-----------------------------------+-----------------------------------+-----------------------------------+------------------------------------+----------------------------------+
-|                         Time|cast(root.sg.d1.s6, "type"="INT32")|cast(root.sg.d1.s6, "type"="INT64")|cast(root.sg.d1.s6, "type"="FLOAT")|cast(root.sg.d1.s6, "type"="DOUBLE")|cast(root.sg.d1.s6, "type"="TEXT")|
-+-----------------------------+-----------------------------------+-----------------------------------+-----------------------------------+------------------------------------+----------------------------------+
-|1970-01-01T08:00:00.001+08:00|                                  0|                                  0|                                0.0|                                 0.0|                             false|
-|1970-01-01T08:00:00.002+08:00|                                  1|                                  1|                                1.0|                                 1.0|                              true|
-|1970-01-01T08:00:00.003+08:00|                                  1|                                  1|                                1.0|                                 1.0|                              true|
-+-----------------------------+-----------------------------------+-----------------------------------+-----------------------------------+------------------------------------+----------------------------------+
-Total line number = 3
-It costs 0.016s
-```
+// cast BOOLEAN to other types
+IoTDB> select cast(s5 as INT32), cast(s5 as INT64),cast(s5 as FLOAT),cast(s5 as DOUBLE), cast(s5 as TEXT) from root.sg.d1
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+---------------------------+
+|                         Time|CAST(root.sg.d1.s5 AS INT32)|CAST(root.sg.d1.s5 AS INT64)|CAST(root.sg.d1.s5 AS FLOAT)|CAST(root.sg.d1.s5 AS DOUBLE)|CAST(root.sg.d1.s5 AS TEXT)|
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+---------------------------+
+|1970-01-01T08:00:00.000+08:00|                           0|                           0|                         0.0|                          0.0|                      false|
+|1970-01-01T08:00:00.001+08:00|                           0|                           0|                         0.0|                          0.0|                      false|
+|1970-01-01T08:00:00.002+08:00|                           1|                           1|                         1.0|                          1.0|                       true|
+|1970-01-01T08:00:00.003+08:00|                           1|                           1|                         1.0|                          1.0|                       true|
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+---------------------------+
 
-3. When TEXT is converted to INT32, INT64, or FLOAT, the TEXT is first converted to DOUBLE and then to the corresponding type, which may cause loss of precision. It will skip directly if the data can not be converted.
+// cast TEXT to numeric types
+IoTDB> select cast(s6 as INT32), cast(s6 as INT64), cast(s6 as FLOAT), cast(s6 as DOUBLE) from root.sg.d1 where time < 2
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+
+|                         Time|CAST(root.sg.d1.s6 AS INT32)|CAST(root.sg.d1.s6 AS INT64)|CAST(root.sg.d1.s6 AS FLOAT)|CAST(root.sg.d1.s6 AS DOUBLE)|
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+
+|1970-01-01T08:00:00.000+08:00|                       10000|                       10000|                     10000.0|                      10000.0|
+|1970-01-01T08:00:00.001+08:00|                           3|                           3|                         3.0|                          3.0|
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+
 
-```
-IoTDB> select cast(s5, 'type'='INT32'), cast(s5, 'type'='INT64'), cast(s5, 'type'='FLOAT') from root.sg.d1;
-+----+-----------------------------------+-----------------------------------+-----------------------------------+
-|Time|cast(root.sg.d1.s5, "type"="INT32")|cast(root.sg.d1.s5, "type"="INT64")|cast(root.sg.d1.s5, "type"="FLOAT")|
-+----+-----------------------------------+-----------------------------------+-----------------------------------+
-+----+-----------------------------------+-----------------------------------+-----------------------------------+
-Empty set.
-It costs 0.005s
+// cast TEXT to BOOLEAN
+IoTDB> select cast(s6 as BOOLEAN) from root.sg.d1 where time >= 2
++-----------------------------+------------------------------+
+|                         Time|CAST(root.sg.d1.s6 AS BOOLEAN)|
++-----------------------------+------------------------------+
+|1970-01-01T08:00:00.002+08:00|                          true|
+|1970-01-01T08:00:00.003+08:00|                         false|
++-----------------------------+------------------------------+
 ```
 
 
 
-#### Syntax
-Example data:
-```
-IoTDB> select text from root.test;
-+-----------------------------+--------------+
-|                         Time|root.test.text|
-+-----------------------------+--------------+
-|1970-01-01T08:00:00.001+08:00|           1.1|
-|1970-01-01T08:00:00.002+08:00|             1|
-|1970-01-01T08:00:00.003+08:00|   hello world|
-|1970-01-01T08:00:00.004+08:00|         false|
-+-----------------------------+--------------+
-```
-SQL:
-```sql
-select cast(text, 'type'='BOOLEAN'), cast(text, 'type'='INT32'), cast(text, 'type'='INT64'), cast(text, 'type'='FLOAT'), cast(text, 'type'='DOUBLE') from root.test;
-```
-Result:
-```
-+-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+
-|                         Time|cast(root.test.text, "type"="BOOLEAN")|cast(root.test.text, "type"="INT32")|cast(root.test.text, "type"="INT64")|cast(root.test.text, "type"="FLOAT")|cast(root.test.text, "type"="DOUBLE")|
-+-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+
-|1970-01-01T08:00:00.001+08:00|                                  true|                                   1|                                   1|                                 1.1|                                  1.1|
-|1970-01-01T08:00:00.002+08:00|                                  true|                                   1|                                   1|                                 1.0|                                  1.0|
-|1970-01-01T08:00:00.003+08:00|                                  true|                                null|                                null|                                null|                                 null|
-|1970-01-01T08:00:00.004+08:00|                                 false|                                null|                                null|                                null|                                 null|
-+-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+
-Total line number = 4
-It costs 0.078s
-```
+
diff --git a/docs/zh/UserGuide/Operators-Functions/Conversion.md b/docs/zh/UserGuide/Operators-Functions/Conversion.md
index 02746ca336..f51efd60b4 100644
--- a/docs/zh/UserGuide/Operators-Functions/Conversion.md
+++ b/docs/zh/UserGuide/Operators-Functions/Conversion.md
@@ -25,107 +25,78 @@
 
 #### 函数简介
 
-当前IoTDB支持6种数据类型,其中包括INT32、INT64、FLOAT、DOUBLE、BOOLEAN以及TEXT。当我们对数据进行查询或者计算时可能需要进行数据类型的转换, 比如说将TEXT转换为INT32,或者提高数据精度,比如说将FLOAT转换为DOUBLE。所以,IoTDB支持使用cast函数对数据类型进行转换。
+当前 IoTDB 支持6种数据类型,其中包括 INT32、INT64、FLOAT、DOUBLE、BOOLEAN 以及 TEXT。当我们对数据进行查询或者计算时可能需要进行数据类型的转换, 比如说将 TEXT 转换为 INT32,或者提高数据精度,比如说将 FLOAT 转换为 DOUBLE。IoTDB 支持使用cast 函数对数据类型进行转换。
 
-| 函数名 | 必要的属性参数                                               | 输出序列类型             | 功能类型                           |
-| ------ | ------------------------------------------------------------ | ------------------------ | ---------------------------------- |
-| CAST   | `type`:输出的数据点的类型,只能是 INT32 / INT64 / FLOAT / DOUBLE / BOOLEAN / TEXT | 由输入属性参数`type`决定 | 将数据转换为`type`参数指定的类型。 |
+语法示例如下:
 
-#### 类型转换说明
+```sql
+SELECT cast(s1 as INT32)from root.sg
+```
+
+cast 函数语法形式上与 PostgreSQL 一致,AS 后指定的数据类型表明要转换成的目标类型,目前 IoTDB 支持的六种数据类型均可以在 cast 函数中使用,遵循的转换规则如下表所示,其中行表示原始数据类型,列表示要转化成的目标数据类型:
 
-1.当INT32、INT64类型的值不为0时,FLOAT与DOUBLE类型的值不为0.0时,TEXT类型不为空字符串或者"false"时,转换为BOOLEAN类型时值为true,否则为false。
+|             | **INT32**                                                    | **INT64**                                                    | **FLOAT**                                       | **DOUBLE**              | **BOOLEAN**                                                  | **TEXT**                         |
+| ----------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------------------------------------------- | ----------------------- | ------------------------------------------------------------ | -------------------------------- |
+| **INT32**   | 不转化                                                       | 直接转化                                                     | 直接转化                                        | 直接转化                | !=0 : true<br />==0: false                                   | String.valueOf()                 |
+| **INT64**   | 超出 INT32 范围:执行抛异常<br />否则:直接转化              | 不转化                                                       | 直接转化                                        | 直接转化                | !=0L : true<br />==0: false                                  | String.valueOf()                 |
+| **FLOAT**   | 超出 INT32 范围:执行抛异常<br />否则:四舍五入(Math.round()) | 超出 INT64 范围:执行抛异常<br />否则:四舍五入(Math.round()) | 不转化                                          | 直接转化                | !=0.0f : true<br />==0: false                                | String.valueOf()                 |
+| **DOUBLE**  | 超出 INT32 范围:执行抛异常<br />否则:四舍五入(Math.round()) | 超出 INT64 范围:执行抛异常<br />否则:四舍五入(Math.round()) | 超出 FLOAT 范围:执行抛异常<br />否则:直接转化 | 不转化                  | !=0.0 : true<br />==0: false                                 | String.valueOf()                 |
+| **BOOLEAN** | true: 1<br />false: 0                                        | true: 1L<br />false: 0                                       | true: 1.0f<br />false: 0                        | true: 1.0<br />false: 0 | 不转化                                                       | true: "true"<br />false: "false" |
+| **TEXT**    | Integer.parseInt()                                           | Long.parseLong()                                             | Float.parseFloat()                              | Double.parseDouble()    | text.toLowerCase =="true" : true<br />text.toLowerCase =="false" : false<br />其它情况:执行抛异常 | 不转化                           |
+
+#### 使用示例
 
 ```
-IoTDB> show timeseries root.sg.d1.*;
-+-------------+-----+-------------+--------+--------+-----------+----+----------+
-|   timeseries|alias|     database|dataType|encoding|compression|tags|attributes|
-+-------------+-----+-------------+--------+--------+-----------+----+----------+
-|root.sg.d1.s3| null|      root.sg|   FLOAT|     RLE|     SNAPPY|null|      null|
-|root.sg.d1.s4| null|      root.sg|  DOUBLE|     RLE|     SNAPPY|null|      null|
-|root.sg.d1.s5| null|      root.sg|    TEXT|   PLAIN|     SNAPPY|null|      null|
-|root.sg.d1.s6| null|      root.sg| BOOLEAN|     RLE|     SNAPPY|null|      null|
-|root.sg.d1.s1| null|      root.sg|   INT32|     RLE|     SNAPPY|null|      null|
-|root.sg.d1.s2| null|      root.sg|   INT64|     RLE|     SNAPPY|null|      null|
-+-------------+-----+-------------+--------+--------+-----------+----+----------+
-Total line number = 6
-It costs 0.006s
+// timeseries
+IoTDB> show timeseries root.sg.d1.**
++-------------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+
+|   Timeseries|Alias|Database|DataType|Encoding|Compression|Tags|Attributes|Deadband|DeadbandParameters|
++-------------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+
+|root.sg.d1.s3| null| root.sg|   FLOAT|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s4| null| root.sg|  DOUBLE|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s5| null| root.sg| BOOLEAN|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s6| null| root.sg|    TEXT|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s1| null| root.sg|   INT32|   PLAIN|     SNAPPY|null|      null|    null|              null|
+|root.sg.d1.s2| null| root.sg|   INT64|   PLAIN|     SNAPPY|null|      null|    null|              null|
++-------------+-----+--------+--------+--------+-----------+----+----------+--------+------------------+
+
+// data of timeseries
 IoTDB> select * from root.sg.d1;
 +-----------------------------+-------------+-------------+-------------+-------------+-------------+-------------+
 |                         Time|root.sg.d1.s3|root.sg.d1.s4|root.sg.d1.s5|root.sg.d1.s6|root.sg.d1.s1|root.sg.d1.s2|
 +-----------------------------+-------------+-------------+-------------+-------------+-------------+-------------+
-|1970-01-01T08:00:00.001+08:00|          1.1|          1.1|         test|        false|            1|            1|
-|1970-01-01T08:00:00.002+08:00|         -2.2|         -2.2|        false|         true|           -2|           -2|
-|1970-01-01T08:00:00.003+08:00|          0.0|          0.0|         true|         true|            0|            0|
+|1970-01-01T08:00:00.000+08:00|          0.0|          0.0|        false|        10000|            0|            0|
+|1970-01-01T08:00:00.001+08:00|          1.0|          1.0|        false|            3|            1|            1|
+|1970-01-01T08:00:00.002+08:00|          2.7|          2.7|         true|         TRue|            2|            2|
+|1970-01-01T08:00:00.003+08:00|         3.33|         3.33|         true|        faLse|            3|            3|
 +-----------------------------+-------------+-------------+-------------+-------------+-------------+-------------+
-Total line number = 3
-It costs 0.009s
-IoTDB> select cast(s1, 'type'='BOOLEAN'), cast(s2, 'type'='BOOLEAN'), cast(s3, 'type'='BOOLEAN'), cast(s4, 'type'='BOOLEAN'), cast(s5, 'type'='BOOLEAN') from root.sg.d1;
-+-----------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+
-|                         Time|cast(root.sg.d1.s1, "type"="BOOLEAN")|cast(root.sg.d1.s2, "type"="BOOLEAN")|cast(root.sg.d1.s3, "type"="BOOLEAN")|cast(root.sg.d1.s4, "type"="BOOLEAN")|cast(root.sg.d1.s5, "type"="BOOLEAN")|
-+-----------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+
-|1970-01-01T08:00:00.001+08:00|                                 true|                                 true|                                 true|                                 true|                                 true|
-|1970-01-01T08:00:00.002+08:00|                                 true|                                 true|                                 true|                                 true|                                false|
-|1970-01-01T08:00:00.003+08:00|                                false|                                false|                                false|                                false|                                 true|
-+-----------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+-------------------------------------+
-Total line number = 3
-It costs 0.012s
-```
-
-2.当BOOLEAN类型的值为true时,转换为INT32与INT64类型的值为1,转换为FLOAT或者DOUBLE类型时值为1.0,转换为TEXT类型时值为"true"。当BOOLEAN类型的值为false时,转换为INT32与INT64类型的值为0,转换为FLOAT或者DOUBLE类型时值为0.0,转换为TEXT类型时值为"false"。
-
-```
-IoTDB> select cast(s6, 'type'='INT32'), cast(s6, 'type'='INT64'), cast(s6, 'type'='FLOAT'), cast(s6, 'type'='DOUBLE'), cast(s6, 'type'='TEXT') from root.sg.d1;
-+-----------------------------+-----------------------------------+-----------------------------------+-----------------------------------+------------------------------------+----------------------------------+
-|                         Time|cast(root.sg.d1.s6, "type"="INT32")|cast(root.sg.d1.s6, "type"="INT64")|cast(root.sg.d1.s6, "type"="FLOAT")|cast(root.sg.d1.s6, "type"="DOUBLE")|cast(root.sg.d1.s6, "type"="TEXT")|
-+-----------------------------+-----------------------------------+-----------------------------------+-----------------------------------+------------------------------------+----------------------------------+
-|1970-01-01T08:00:00.001+08:00|                                  0|                                  0|                                0.0|                                 0.0|                             false|
-|1970-01-01T08:00:00.002+08:00|                                  1|                                  1|                                1.0|                                 1.0|                              true|
-|1970-01-01T08:00:00.003+08:00|                                  1|                                  1|                                1.0|                                 1.0|                              true|
-+-----------------------------+-----------------------------------+-----------------------------------+-----------------------------------+------------------------------------+----------------------------------+
-Total line number = 3
-It costs 0.016s
-```
-
-3.当TEXT类型转换为INT32、INT64、FLOAT类型时,会先将TEXT类型的数据转换为DOUBLE类型,然后再转换为对应的类型,此时可能会存在损失精度的问题。如果无法转换的话则直接跳过。
 
-```
-IoTDB> select cast(s5, 'type'='INT32'), cast(s5, 'type'='INT64'), cast(s5, 'type'='FLOAT') from root.sg.d1;
-+----+-----------------------------------+-----------------------------------+-----------------------------------+
-|Time|cast(root.sg.d1.s5, "type"="INT32")|cast(root.sg.d1.s5, "type"="INT64")|cast(root.sg.d1.s5, "type"="FLOAT")|
-+----+-----------------------------------+-----------------------------------+-----------------------------------+
-+----+-----------------------------------+-----------------------------------+-----------------------------------+
-Empty set.
-It costs 0.009s
-```
-
-#### 使用示例
-
-测试数据:
-```
-IoTDB> select text from root.test;
-+-----------------------------+--------------+
-|                         Time|root.test.text|
-+-----------------------------+--------------+
-|1970-01-01T08:00:00.001+08:00|           1.1|
-|1970-01-01T08:00:00.002+08:00|             1|
-|1970-01-01T08:00:00.003+08:00|   hello world|
-|1970-01-01T08:00:00.004+08:00|         false|
-+-----------------------------+--------------+
-```
-SQL语句:
-```sql
-select cast(text, 'type'='BOOLEAN'), cast(text, 'type'='INT32'), cast(text, 'type'='INT64'), cast(text, 'type'='FLOAT'), cast(text, 'type'='DOUBLE') from root.test;
-```
-结果:
-```
-+-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+
-|                         Time|cast(root.test.text, "type"="BOOLEAN")|cast(root.test.text, "type"="INT32")|cast(root.test.text, "type"="INT64")|cast(root.test.text, "type"="FLOAT")|cast(root.test.text, "type"="DOUBLE")|
-+-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+
-|1970-01-01T08:00:00.001+08:00|                                  true|                                   1|                                   1|                                 1.1|                                  1.1|
-|1970-01-01T08:00:00.002+08:00|                                  true|                                   1|                                   1|                                 1.0|                                  1.0|
-|1970-01-01T08:00:00.003+08:00|                                  true|                                null|                                null|                                null|                                 null|
-|1970-01-01T08:00:00.004+08:00|                                 false|                                null|                                null|                                null|                                 null|
-+-----------------------------+--------------------------------------+------------------------------------+------------------------------------+------------------------------------+-------------------------------------+
-Total line number = 4
-It costs 0.078s
+// cast BOOLEAN to other types
+IoTDB> select cast(s5 as INT32), cast(s5 as INT64),cast(s5 as FLOAT),cast(s5 as DOUBLE), cast(s5 as TEXT) from root.sg.d1
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+---------------------------+
+|                         Time|CAST(root.sg.d1.s5 AS INT32)|CAST(root.sg.d1.s5 AS INT64)|CAST(root.sg.d1.s5 AS FLOAT)|CAST(root.sg.d1.s5 AS DOUBLE)|CAST(root.sg.d1.s5 AS TEXT)|
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+---------------------------+
+|1970-01-01T08:00:00.000+08:00|                           0|                           0|                         0.0|                          0.0|                      false|
+|1970-01-01T08:00:00.001+08:00|                           0|                           0|                         0.0|                          0.0|                      false|
+|1970-01-01T08:00:00.002+08:00|                           1|                           1|                         1.0|                          1.0|                       true|
+|1970-01-01T08:00:00.003+08:00|                           1|                           1|                         1.0|                          1.0|                       true|
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+---------------------------+
+
+// cast TEXT to numeric types
+IoTDB> select cast(s6 as INT32), cast(s6 as INT64), cast(s6 as FLOAT), cast(s6 as DOUBLE) from root.sg.d1 where time < 2
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+
+|                         Time|CAST(root.sg.d1.s6 AS INT32)|CAST(root.sg.d1.s6 AS INT64)|CAST(root.sg.d1.s6 AS FLOAT)|CAST(root.sg.d1.s6 AS DOUBLE)|
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+
+|1970-01-01T08:00:00.000+08:00|                       10000|                       10000|                     10000.0|                      10000.0|
+|1970-01-01T08:00:00.001+08:00|                           3|                           3|                         3.0|                          3.0|
++-----------------------------+----------------------------+----------------------------+----------------------------+-----------------------------+
+
+// cast TEXT to BOOLEAN
+IoTDB> select cast(s6 as BOOLEAN) from root.sg.d1 where time >= 2
++-----------------------------+------------------------------+
+|                         Time|CAST(root.sg.d1.s6 AS BOOLEAN)|
++-----------------------------+------------------------------+
+|1970-01-01T08:00:00.002+08:00|                          true|
+|1970-01-01T08:00:00.003+08:00|                         false|
++-----------------------------+------------------------------+
 ```
diff --git a/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/ConstValue.java b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/ConstValue.java
new file mode 100644
index 0000000000..eb009282e9
--- /dev/null
+++ b/integration-test/src/main/java/org/apache/iotdb/db/query/udf/example/ConstValue.java
@@ -0,0 +1,42 @@
+/*
+ * 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.udf.api.UDTF;
+import org.apache.iotdb.udf.api.access.Row;
+import org.apache.iotdb.udf.api.collector.PointCollector;
+import org.apache.iotdb.udf.api.customizer.config.UDTFConfigurations;
+import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
+import org.apache.iotdb.udf.api.customizer.strategy.RowByRowAccessStrategy;
+import org.apache.iotdb.udf.api.type.Type;
+
+// for test
+public class ConstValue implements UDTF {
+
+  @Override
+  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations) {
+    configurations.setAccessStrategy(new RowByRowAccessStrategy()).setOutputDataType(Type.INT32);
+  }
+
+  @Override
+  public void transform(Row row, PointCollector collector) throws Exception {
+    collector.putInt(row.getTime(), 1);
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java b/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinScalarFunctionEnum.java
similarity index 72%
copy from server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
copy to integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinScalarFunctionEnum.java
index 8d13d370a9..bd38e182cd 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
+++ b/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinScalarFunctionEnum.java
@@ -17,11 +17,20 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.mpp.plan.expression.multi;
+package org.apache.iotdb.itbase.constant;
 
-/** */
-public enum FunctionType {
-  AGGREGATION_FUNCTION,
-  BUILT_IN_FUNCTION,
-  UDF
+public enum BuiltinScalarFunctionEnum {
+  DIFF("diff"),
+  CAST("cast"),
+  ;
+
+  private final String functionName;
+
+  BuiltinScalarFunctionEnum(String functionName) {
+    this.functionName = functionName;
+  }
+
+  public String getFunctionName() {
+    return functionName;
+  }
 }
diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinTimeSeriesGeneratingFunctionEnum.java b/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinTimeSeriesGeneratingFunctionEnum.java
index fa76bfe333..2b98a13fd9 100644
--- a/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinTimeSeriesGeneratingFunctionEnum.java
+++ b/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinTimeSeriesGeneratingFunctionEnum.java
@@ -63,7 +63,6 @@ public enum BuiltinTimeSeriesGeneratingFunctionEnum {
   NON_NEGATIVE_DERIVATIVE("NON_NEGATIVE_DERIVATIVE"),
   TOP_K("TOP_K"),
   BOTTOM_K("BOTTOM_K"),
-  CAST("CAST"),
   IN_RANGE("IN_RANGE"),
   ON_OFF("ON_OFF"),
   ZERO_DURATION("ZERO_DURATION"),
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java
index 2d9355eb70..ceb48cd4c5 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBSyntaxConventionStringLiteralIT.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.it.env.EnvFactory;
 import org.apache.iotdb.it.framework.IoTDBTestRunner;
 import org.apache.iotdb.itbase.category.ClusterIT;
 import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+import org.apache.iotdb.itbase.constant.BuiltinScalarFunctionEnum;
 import org.apache.iotdb.itbase.constant.BuiltinTimeSeriesGeneratingFunctionEnum;
 import org.apache.iotdb.itbase.constant.TestConstant;
 import org.apache.iotdb.rpc.TSStatusCode;
@@ -334,7 +335,11 @@ public class IoTDBSyntaxConventionStringLiteralIT {
           }
           ++count;
         }
-        Assert.assertEquals(1 + BuiltinTimeSeriesGeneratingFunctionEnum.values().length, count);
+        Assert.assertEquals(
+            1
+                + BuiltinTimeSeriesGeneratingFunctionEnum.values().length
+                + BuiltinScalarFunctionEnum.values().length,
+            count);
       }
       statement.execute("drop function udf");
 
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/builtinfunction/scalar/IoTDBCastFunctionIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/builtinfunction/scalar/IoTDBCastFunctionIT.java
new file mode 100644
index 0000000000..fb14be551e
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/builtinfunction/scalar/IoTDBCastFunctionIT.java
@@ -0,0 +1,1032 @@
+/*
+ * 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.it.builtinfunction.scalar;
+
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.apache.iotdb.db.it.utils.TestUtils.prepareData;
+import static org.apache.iotdb.db.it.utils.TestUtils.resultSetEqualTest;
+import static org.apache.iotdb.itbase.constant.TestConstant.TIMESTAMP_STR;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBCastFunctionIT {
+  private static final String[] SQLs =
+      new String[] {
+        // normal cases
+        "CREATE DATABASE root.sg",
+        "CREATE TIMESERIES root.sg.d1.s1 WITH DATATYPE=INT32, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.sg.d1.s2 WITH DATATYPE=INT64, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.sg.d1.s3 WITH DATATYPE=FLOAT, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.sg.d1.s4 WITH DATATYPE=DOUBLE, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.sg.d1.s5 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.sg.d1.s6 WITH DATATYPE=TEXT, ENCODING=PLAIN",
+        // data for int series
+        "INSERT INTO root.sg.d1(timestamp,s1) values(0, 0)",
+        "INSERT INTO root.sg.d1(timestamp,s1) values(1, 1)",
+        "INSERT INTO root.sg.d1(timestamp,s1) values(2, 2)",
+        "INSERT INTO root.sg.d1(timestamp,s1) values(3, 3)",
+        // data for long series
+        "INSERT INTO root.sg.d1(timestamp,s2) values(0, 0)",
+        "INSERT INTO root.sg.d1(timestamp,s2) values(1, 1)",
+        "INSERT INTO root.sg.d1(timestamp,s2) values(2, 2)",
+        "INSERT INTO root.sg.d1(timestamp,s2) values(3, 3)",
+        // data for float series
+        "INSERT INTO root.sg.d1(timestamp,s3) values(0, 0)",
+        "INSERT INTO root.sg.d1(timestamp,s3) values(1, 1)",
+        "INSERT INTO root.sg.d1(timestamp,s3) values(2, 2.7)",
+        "INSERT INTO root.sg.d1(timestamp,s3) values(3, 3.33)",
+        // data for double series
+        "INSERT INTO root.sg.d1(timestamp,s4) values(0, 0)",
+        "INSERT INTO root.sg.d1(timestamp,s4) values(1, 1.0)",
+        "INSERT INTO root.sg.d1(timestamp,s4) values(2, 2.7)",
+        "INSERT INTO root.sg.d1(timestamp,s4) values(3, 3.33)",
+        // data for boolean series
+        "INSERT INTO root.sg.d1(timestamp,s5) values(0, false)",
+        "INSERT INTO root.sg.d1(timestamp,s5) values(1, false)",
+        "INSERT INTO root.sg.d1(timestamp,s5) values(2, true)",
+        "INSERT INTO root.sg.d1(timestamp,s5) values(3, true)",
+        // data for text series
+        "INSERT INTO root.sg.d1(timestamp,s6) values(0, \"10000\")",
+        "INSERT INTO root.sg.d1(timestamp,s6) values(1, \"3\")",
+        "INSERT INTO root.sg.d1(timestamp,s6) values(2, \"TRue\")",
+        "INSERT INTO root.sg.d1(timestamp,s6) values(3, \"faLse\")",
+        "flush",
+
+        // special cases
+        "create DATABASE root.sg1",
+        "create timeseries root.sg1.d1.s1 WITH DATATYPE=INT32, ENCODING=PLAIN",
+        "create timeseries root.sg1.d1.s2 WITH DATATYPE=INT64, ENCODING=PLAIN",
+        "create timeseries root.sg1.d1.s3 WITH DATATYPE=FLOAT, ENCODING=PLAIN",
+        "create timeseries root.sg1.d1.s4 WITH DATATYPE=DOUBLE, ENCODING=PLAIN",
+        "create timeseries root.sg1.d1.s5 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN",
+        "create timeseries root.sg1.d1.s6 WITH DATATYPE=TEXT, ENCODING=PLAIN",
+        "INSERT INTO root.sg1.d1(timestamp,s2) values(1, 2147483648)",
+        "INSERT INTO root.sg1.d1(timestamp,s3) values(1, 2147483648.0)",
+        "INSERT INTO root.sg1.d1(timestamp,s3) values(2, 2e38)",
+        "INSERT INTO root.sg1.d1(timestamp,s4) values(1, 4e50)",
+        "INSERT INTO root.sg1.d1(timestamp,s6) values(1, \"test\")",
+        "INSERT INTO root.sg1.d1(timestamp,s6) values(2, \"1.1\")",
+        "INSERT INTO root.sg1.d1(timestamp,s6) values(3, \"4e60\")",
+        "INSERT INTO root.sg1.d1(timestamp,s6) values(4, \"4e60000\")",
+      };
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvFactory.getEnv().initClusterEnvironment();
+    prepareData(SQLs);
+    registerUDF();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvFactory.getEnv().cleanClusterEnvironment();
+  }
+
+  private static void registerUDF() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute(
+          "create function constvalue as 'org.apache.iotdb.db.query.udf.example.ConstValue'");
+    } catch (SQLException throwable) {
+      fail(throwable.getMessage());
+    }
+  }
+
+  // region ================== New Transformer ==================
+  @Test
+  public void testNewTransformerWithIntSource() {
+    // cast to int
+    String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s1 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,2,", "3,3,",
+        };
+    resultSetEqualTest("select CAST(s1 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s1 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,2,", "3,3,",
+        };
+    resultSetEqualTest(
+        "select CAST(s1 AS INT64) from root.sg.d1", longExpectedHeader, longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s1 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.0,", "3,3.0,",
+        };
+    resultSetEqualTest(
+        "select CAST(s1 AS FLOAT) from root.sg.d1", floatExpectedHeader, floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s1 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.0,", "3,3.0,",
+        };
+    resultSetEqualTest(
+        "select CAST(s1 AS DOUBLE) from root.sg.d1", doubleExpectedHeader, doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s1 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,false,", "1,true,", "2,true,", "3,true,",
+        };
+    resultSetEqualTest(
+        "select CAST(s1 AS BOOLEAN) from root.sg.d1", booleanExpectedHeader, booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s1 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,2,", "3,3,",
+        };
+    resultSetEqualTest("select CAST(s1 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testNewTransformerWithLongSource() {
+    // cast to int
+    String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s2 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,2,", "3,3,",
+        };
+    resultSetEqualTest("select CAST(s2 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s2 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,2,", "3,3,",
+        };
+    resultSetEqualTest(
+        "select CAST(s2 AS INT64) from root.sg.d1", longExpectedHeader, longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s2 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.0,", "3,3.0,",
+        };
+    resultSetEqualTest(
+        "select CAST(s2 AS FLOAT) from root.sg.d1", floatExpectedHeader, floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s2 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.0,", "3,3.0,",
+        };
+    resultSetEqualTest(
+        "select CAST(s2 AS DOUBLE) from root.sg.d1", doubleExpectedHeader, doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s2 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,false,", "1,true,", "2,true,", "3,true,",
+        };
+    resultSetEqualTest(
+        "select CAST(s2 AS BOOLEAN) from root.sg.d1", booleanExpectedHeader, booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s2 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,2,", "3,3,",
+        };
+    resultSetEqualTest("select CAST(s2 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testNewTransformerWithFloatSource() {
+    // cast to int
+    String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s3 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,3,", "3,3,",
+        };
+    resultSetEqualTest("select CAST(s3 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s3 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,3,", "3,3,",
+        };
+    resultSetEqualTest(
+        "select CAST(s3 AS INT64) from root.sg.d1", longExpectedHeader, longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s3 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.7,", "3,3.33,",
+        };
+    resultSetEqualTest(
+        "select CAST(s3 AS FLOAT) from root.sg.d1", floatExpectedHeader, floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s3 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.700000047683716,", "3,3.3299999237060547,",
+        };
+    resultSetEqualTest(
+        "select CAST(s3 AS DOUBLE) from root.sg.d1", doubleExpectedHeader, doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s3 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,false,", "1,true,", "2,true,", "3,true,",
+        };
+    resultSetEqualTest(
+        "select CAST(s3 AS BOOLEAN) from root.sg.d1", booleanExpectedHeader, booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s3 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.7,", "3,3.33,",
+        };
+    resultSetEqualTest("select CAST(s3 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testNewTransformerWithDoubleSource() {
+    // cast to int
+    String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s4 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,3,", "3,3,",
+        };
+    resultSetEqualTest("select CAST(s4 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s4 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,0,", "1,1,", "2,3,", "3,3,",
+        };
+    resultSetEqualTest(
+        "select CAST(s4 AS INT64) from root.sg.d1", longExpectedHeader, longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s4 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.7,", "3,3.33,",
+        };
+    resultSetEqualTest(
+        "select CAST(s4 AS FLOAT) from root.sg.d1", floatExpectedHeader, floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s4 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.7,", "3,3.33,",
+        };
+    resultSetEqualTest(
+        "select CAST(s4 AS DOUBLE) from root.sg.d1", doubleExpectedHeader, doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s4 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,false,", "1,true,", "2,true,", "3,true,",
+        };
+    resultSetEqualTest(
+        "select CAST(s4 AS BOOLEAN) from root.sg.d1", booleanExpectedHeader, booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s4 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,0.0,", "1,1.0,", "2,2.7,", "3,3.33,",
+        };
+    resultSetEqualTest("select CAST(s4 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testNewTransformerWithBooleanSource() {
+    // cast to int
+    String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s5 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,0,", "1,0,", "2,1,", "3,1,",
+        };
+    resultSetEqualTest("select CAST(s5 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s5 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,0,", "1,0,", "2,1,", "3,1,",
+        };
+    resultSetEqualTest(
+        "select CAST(s5 AS INT64) from root.sg.d1", longExpectedHeader, longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s5 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,0.0,", "1,0.0,", "2,1.0,", "3,1.0,",
+        };
+    resultSetEqualTest(
+        "select CAST(s5 AS FLOAT) from root.sg.d1", floatExpectedHeader, floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s5 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,0.0,", "1,0.0,", "2,1.0,", "3,1.0,",
+        };
+    resultSetEqualTest(
+        "select CAST(s5 AS DOUBLE) from root.sg.d1", doubleExpectedHeader, doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s5 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,false,", "1,false,", "2,true,", "3,true,",
+        };
+    resultSetEqualTest(
+        "select CAST(s5 AS BOOLEAN) from root.sg.d1", booleanExpectedHeader, booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s5 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,false,", "1,false,", "2,true,", "3,true,",
+        };
+    resultSetEqualTest("select CAST(s5 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testNewTransformerWithTextSource() {
+    // cast to int
+    String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s6 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,10000,", "1,3,",
+        };
+    resultSetEqualTest(
+        "select CAST(s6 AS INT32) from root.sg.d1 where time < 2", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s6 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,10000,", "1,3,",
+        };
+    resultSetEqualTest(
+        "select CAST(s6 AS INT64) from root.sg.d1 where time < 2",
+        longExpectedHeader,
+        longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s6 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,10000.0,", "1,3.0,",
+        };
+    resultSetEqualTest(
+        "select CAST(s6 AS FLOAT) from root.sg.d1 where time < 2",
+        floatExpectedHeader,
+        floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s6 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,10000.0,", "1,3.0,",
+        };
+    resultSetEqualTest(
+        "select CAST(s6 AS DOUBLE) from root.sg.d1 where time < 2",
+        doubleExpectedHeader,
+        doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s6 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "2,true,", "3,false,",
+        };
+    resultSetEqualTest(
+        "select CAST(s6 AS BOOLEAN) from root.sg.d1 where time >= 2",
+        booleanExpectedHeader,
+        booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader = new String[] {TIMESTAMP_STR, "CAST(root.sg.d1.s6 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,10000,", "1,3,", "2,TRue,", "3,faLse,",
+        };
+    resultSetEqualTest("select CAST(s6 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  // endregion
+
+  // region ================== Old Transformer ==================
+
+  @Test
+  public void testOldTransformerWithIntSource() {
+    // cast to int
+    String[] intExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s1),CAST(root.sg.d1.s1 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,2,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s1),CAST(s1 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s1),CAST(root.sg.d1.s1 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,2,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s1),CAST(s1 AS INT64) from root.sg.d1",
+        longExpectedHeader,
+        longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s1),CAST(root.sg.d1.s1 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.0,", "3,1,3.0,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s1),CAST(s1 AS FLOAT) from root.sg.d1",
+        floatExpectedHeader,
+        floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s1),CAST(root.sg.d1.s1 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.0,", "3,1,3.0,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s1),CAST(s1 AS DOUBLE) from root.sg.d1",
+        doubleExpectedHeader,
+        doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s1),CAST(root.sg.d1.s1 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,1,false,", "1,1,true,", "2,1,true,", "3,1,true,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s1),CAST(s1 AS BOOLEAN) from root.sg.d1",
+        booleanExpectedHeader,
+        booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s1),CAST(root.sg.d1.s1 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,2,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s1),CAST(s1 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testOldTransformerWithLongSource() {
+    // cast to int
+    String[] intExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s2),CAST(root.sg.d1.s2 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,2,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s2),CAST(s2 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s2),CAST(root.sg.d1.s2 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,2,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s2),CAST(s2 AS INT64) from root.sg.d1",
+        longExpectedHeader,
+        longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s2),CAST(root.sg.d1.s2 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.0,", "3,1,3.0,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s2),CAST(s2 AS FLOAT) from root.sg.d1",
+        floatExpectedHeader,
+        floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s2),CAST(root.sg.d1.s2 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.0,", "3,1,3.0,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s2),CAST(s2 AS DOUBLE) from root.sg.d1",
+        doubleExpectedHeader,
+        doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s2),CAST(root.sg.d1.s2 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,1,false,", "1,1,true,", "2,1,true,", "3,1,true,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s2),CAST(s2 AS BOOLEAN) from root.sg.d1",
+        booleanExpectedHeader,
+        booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s2),CAST(root.sg.d1.s2 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,2,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s2),CAST(s2 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testOldTransformerWithFloatSource() {
+    // cast to int
+    String[] intExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s3),CAST(root.sg.d1.s3 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,3,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s3),CAST(s3 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s3),CAST(root.sg.d1.s3 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,3,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s3),CAST(s3 AS INT64) from root.sg.d1",
+        longExpectedHeader,
+        longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s3),CAST(root.sg.d1.s3 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.7,", "3,1,3.33,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s3),CAST(s3 AS FLOAT) from root.sg.d1",
+        floatExpectedHeader,
+        floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s3),CAST(root.sg.d1.s3 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.700000047683716,", "3,1,3.3299999237060547,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s3),CAST(s3 AS DOUBLE) from root.sg.d1",
+        doubleExpectedHeader,
+        doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s3),CAST(root.sg.d1.s3 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,1,false,", "1,1,true,", "2,1,true,", "3,1,true,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s3),CAST(s3 AS BOOLEAN) from root.sg.d1",
+        booleanExpectedHeader,
+        booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s3),CAST(root.sg.d1.s3 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.7,", "3,1,3.33,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s3),CAST(s3 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testOldTransformerWithDoubleSource() {
+    // cast to int
+    String[] intExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s4),CAST(root.sg.d1.s4 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,3,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s4),CAST(s4 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s4),CAST(root.sg.d1.s4 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,1,0,", "1,1,1,", "2,1,3,", "3,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s4),CAST(s4 AS INT64) from root.sg.d1",
+        longExpectedHeader,
+        longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s4),CAST(root.sg.d1.s4 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.7,", "3,1,3.33,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s4),CAST(s4 AS FLOAT) from root.sg.d1",
+        floatExpectedHeader,
+        floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s4),CAST(root.sg.d1.s4 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.7,", "3,1,3.33,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s4),CAST(s4 AS DOUBLE) from root.sg.d1",
+        doubleExpectedHeader,
+        doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s4),CAST(root.sg.d1.s4 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,1,false,", "1,1,true,", "2,1,true,", "3,1,true,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s4),CAST(s4 AS BOOLEAN) from root.sg.d1",
+        booleanExpectedHeader,
+        booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s4),CAST(root.sg.d1.s4 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,1.0,", "2,1,2.7,", "3,1,3.33,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s4),CAST(s4 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testOldTransformerWithBooleanSource() {
+    // cast to int
+    String[] intExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s5),CAST(root.sg.d1.s5 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,1,0,", "1,1,0,", "2,1,1,", "3,1,1,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s5),CAST(s5 AS INT32) from root.sg.d1", intExpectedHeader, intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s5),CAST(root.sg.d1.s5 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,1,0,", "1,1,0,", "2,1,1,", "3,1,1,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s5),CAST(s5 AS INT64) from root.sg.d1",
+        longExpectedHeader,
+        longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s5),CAST(root.sg.d1.s5 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,0.0,", "2,1,1.0,", "3,1,1.0,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s5),CAST(s5 AS FLOAT) from root.sg.d1",
+        floatExpectedHeader,
+        floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s5),CAST(root.sg.d1.s5 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,1,0.0,", "1,1,0.0,", "2,1,1.0,", "3,1,1.0,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s5),CAST(s5 AS DOUBLE) from root.sg.d1",
+        doubleExpectedHeader,
+        doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s5),CAST(root.sg.d1.s5 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "0,1,false,", "1,1,false,", "2,1,true,", "3,1,true,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s5),CAST(s5 AS BOOLEAN) from root.sg.d1",
+        booleanExpectedHeader,
+        booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s5),CAST(root.sg.d1.s5 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,1,false,", "1,1,false,", "2,1,true,", "3,1,true,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s5),CAST(s5 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  @Test
+  public void testOldTransformerWithTextSource() {
+    // cast to int
+    String[] intExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s6),CAST(root.sg.d1.s6 AS INT32)"};
+    String[] intRetArray =
+        new String[] {
+          "0,1,10000,", "1,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s6),CAST(s6 AS INT32) from root.sg.d1 where time < 2",
+        intExpectedHeader,
+        intRetArray);
+
+    // cast to long
+    String[] longExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s6),CAST(root.sg.d1.s6 AS INT64)"};
+    String[] longRetArray =
+        new String[] {
+          "0,1,10000,", "1,1,3,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s6),CAST(s6 AS INT64) from root.sg.d1 where time < 2",
+        longExpectedHeader,
+        longRetArray);
+
+    // cast to float
+    String[] floatExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s6),CAST(root.sg.d1.s6 AS FLOAT)"};
+    String[] floatRetArray =
+        new String[] {
+          "0,1,10000.0,", "1,1,3.0,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s6),CAST(s6 AS FLOAT) from root.sg.d1 where time < 2",
+        floatExpectedHeader,
+        floatRetArray);
+
+    // cast to double
+    String[] doubleExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s6),CAST(root.sg.d1.s6 AS DOUBLE)"};
+    String[] doubleRetArray =
+        new String[] {
+          "0,1,10000.0,", "1,1,3.0,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s6),CAST(s6 AS DOUBLE) from root.sg.d1 where time < 2",
+        doubleExpectedHeader,
+        doubleRetArray);
+
+    // cast to boolean
+    String[] booleanExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s6),CAST(root.sg.d1.s6 AS BOOLEAN)"};
+    String[] booleanRetArray =
+        new String[] {
+          "2,1,true,", "3,1,false,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s6),CAST(s6 AS BOOLEAN) from root.sg.d1 where time >= 2",
+        booleanExpectedHeader,
+        booleanRetArray);
+
+    // cast to text
+    String[] textExpectedHeader =
+        new String[] {TIMESTAMP_STR, "constvalue(root.sg.d1.s6),CAST(root.sg.d1.s6 AS TEXT)"};
+    String[] textRetArray =
+        new String[] {
+          "0,1,10000,", "1,1,3,", "2,1,TRue,", "3,1,faLse,",
+        };
+    resultSetEqualTest(
+        "select constvalue(s6),CAST(s6 AS TEXT) from root.sg.d1", textExpectedHeader, textRetArray);
+  }
+
+  // endregion
+
+  // region special cases
+
+  @Test
+  public void testCastWithLongSource() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try {
+        statement.execute("select CAST(s2 AS INT32) from root.sg1.d1");
+        fail();
+      } catch (Exception ignored) {
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testCastWithFloatSource() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try {
+        statement.execute("select CAST(s3 AS INT32) from root.sg1.d1");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s3 AS INT64) from root.sg1.d1");
+        fail();
+      } catch (Exception ignored) {
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testCastWithDoubleSource() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try {
+        statement.execute("select CAST(s4 AS INT32) from root.sg1.d1");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s4 AS INT64) from root.sg1.d1");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s4 AS Float) from root.sg1.d1");
+        fail();
+      } catch (Exception ignored) {
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  @Test
+  public void testCastWithTextSource() {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try {
+        statement.execute("select CAST(s6 AS INT32) from root.sg1.d1 where time = 1");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s6 AS INT32) from root.sg1.d1 where time = 2");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s6 AS INT64) from root.sg1.d1 where time = 1");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s6 AS INT64) from root.sg1.d1 where time = 2");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s6 AS FLOAT) from root.sg1.d1 where time=3");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s6 AS FLOAT) from root.sg1.d1 where time=1");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s6 AS DOUBLE) from root.sg1.d1 where time = 1");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s6 AS DOUBLE) from root.sg1.d1 where time = 4");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+      try {
+        statement.execute("select CAST(s6 AS BOOLEAN) from root.sg1.d1 where time = 1");
+        fail();
+      } catch (Exception ignored) {
+      }
+
+    } catch (SQLException e) {
+      e.printStackTrace();
+      fail();
+    }
+  }
+
+  // endregion
+
+}
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDFManagementIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDFManagementIT.java
index 2362af361f..c242a58e88 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDFManagementIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDFManagementIT.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.it.framework.IoTDBTestRunner;
 import org.apache.iotdb.itbase.category.ClusterIT;
 import org.apache.iotdb.itbase.category.LocalStandaloneIT;
 import org.apache.iotdb.itbase.constant.BuiltinAggregationFunctionEnum;
+import org.apache.iotdb.itbase.constant.BuiltinScalarFunctionEnum;
 import org.apache.iotdb.itbase.constant.BuiltinTimeSeriesGeneratingFunctionEnum;
 
 import org.junit.After;
@@ -50,6 +51,9 @@ public class IoTDBUDFManagementIT {
   private static final int BUILTIN_FUNCTIONS_COUNT =
       BuiltinTimeSeriesGeneratingFunctionEnum.values().length;
 
+  private static final int BUILTIN_SCALAR_FUNCTIONS_COUNT =
+      BuiltinScalarFunctionEnum.values().length;
+
   private static final String FUNCTION_TYPE_NATIVE = "native";
   private static final String FUNCTION_TYPE_BUILTIN_UDTF = "built-in UDTF";
   private static final String FUNCTION_TYPE_EXTERNAL_UDTF = "external UDTF";
@@ -85,7 +89,7 @@ public class IoTDBUDFManagementIT {
           }
           ++count;
         }
-        Assert.assertEquals(1 + BUILTIN_FUNCTIONS_COUNT, count);
+        Assert.assertEquals(1 + BUILTIN_FUNCTIONS_COUNT + BUILTIN_SCALAR_FUNCTIONS_COUNT, count);
         statement.execute("drop function udf");
       }
     } catch (SQLException throwable) {
@@ -105,7 +109,9 @@ public class IoTDBUDFManagementIT {
         while (resultSet.next()) {
           ++count;
         }
-        Assert.assertEquals(1 + NATIVE_FUNCTIONS_COUNT + BUILTIN_FUNCTIONS_COUNT, count);
+        Assert.assertEquals(
+            1 + NATIVE_FUNCTIONS_COUNT + BUILTIN_FUNCTIONS_COUNT + BUILTIN_SCALAR_FUNCTIONS_COUNT,
+            count);
         assertEquals(3, resultSet.getMetaData().getColumnCount());
         statement.execute("drop function udf");
 
@@ -118,7 +124,9 @@ public class IoTDBUDFManagementIT {
         while (resultSet.next()) {
           ++count;
         }
-        Assert.assertEquals(1 + NATIVE_FUNCTIONS_COUNT + BUILTIN_FUNCTIONS_COUNT, count);
+        Assert.assertEquals(
+            1 + NATIVE_FUNCTIONS_COUNT + BUILTIN_FUNCTIONS_COUNT + BUILTIN_SCALAR_FUNCTIONS_COUNT,
+            count);
         assertEquals(3, resultSet.getMetaData().getColumnCount());
         statement.execute("drop function udf");
       }
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFBuiltinFunctionIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFBuiltinScalarFunctionIT.java
similarity index 99%
rename from integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFBuiltinFunctionIT.java
rename to integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFBuiltinScalarFunctionIT.java
index 33e2b1e54c..51f894438d 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFBuiltinFunctionIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/udf/IoTDBUDTFBuiltinScalarFunctionIT.java
@@ -44,7 +44,7 @@ import static org.junit.Assert.fail;
 
 @RunWith(IoTDBTestRunner.class)
 @Category({LocalStandaloneIT.class, ClusterIT.class})
-public class IoTDBUDTFBuiltinFunctionIT {
+public class IoTDBUDTFBuiltinScalarFunctionIT {
 
   private static final String[] INSERTION_SQLS = {
     "insert into root.sg.d1(time, s1, s2, s3, s4, s5, s6, s7, s8) values (0, 0, 0, 0, 0, true, '0', 0, 0)",
diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionSimpleIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionSimpleIT.java
index bf9f07ea2e..cadf2c3dd5 100644
--- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionSimpleIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionSimpleIT.java
@@ -1282,13 +1282,13 @@ public class IoTDBSessionSimpleIT {
       session.insertRecordsOfOneDevice(deviceId, times, measurementsList, typesList, valuesList);
 
       // excepted
-      String[] targetTypes = {"INT64", "INT32", "DOUBLE", "FLOAT", "TEXT", "BOOLEAN"};
+      String[] targetTypes = {"INT64", "INT32", "DOUBLE", "FLOAT", "TEXT"};
       String[] excepted = {
-        "0\t0\t1\t0.0\t0.0\ttrue\ttrue",
-        "2\t1\t2\t1.0\t2.0\tfalse\ttrue",
-        "4\t2\t3\t2.0\t4.0\ttrue\ttrue",
-        "6\t3\t4\t3.0\t6.0\tfalse\ttrue",
-        "8\t4\t5\t4.0\t8.0\ttrue\ttrue"
+        "0\t0\t1\t0.0\t0.0\ttrue",
+        "2\t1\t2\t1.0\t2.0\tfalse",
+        "4\t2\t3\t2.0\t4.0\ttrue",
+        "6\t3\t4\t3.0\t6.0\tfalse",
+        "8\t4\t5\t4.0\t8.0\ttrue"
       };
 
       // query
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
index 92c6a6aa77..293913aa8a 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
@@ -159,6 +159,7 @@ public class IoTDBConstant {
   public static final String COLUMN_SCHEMA_TEMPLATE = "template name";
 
   public static final String FUNCTION_TYPE_NATIVE = "native";
+  public static final String FUNCTION_TYPE_BUILTIN_SCALAR = "built-in scalar";
   public static final String FUNCTION_TYPE_BUILTIN_UDAF = "built-in UDAF";
   public static final String FUNCTION_TYPE_BUILTIN_UDTF = "built-in UDTF";
   public static final String FUNCTION_TYPE_EXTERNAL_UDAF = "external UDAF";
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinFunction.java b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinScalarFunction.java
similarity index 77%
rename from node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinFunction.java
rename to node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinScalarFunction.java
index 1c64b99d15..03cd7abe1b 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinFunction.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinScalarFunction.java
@@ -26,13 +26,14 @@ import java.util.HashSet;
 import java.util.Set;
 import java.util.stream.Collectors;
 
-public enum BuiltinFunction {
+public enum BuiltinScalarFunction {
   DIFF("diff"),
+  CAST("cast"),
   ;
 
   private final String functionName;
 
-  BuiltinFunction(String functionName) {
+  BuiltinScalarFunction(String functionName) {
     this.functionName = functionName;
   }
 
@@ -42,8 +43,8 @@ public enum BuiltinFunction {
 
   private static final Set<String> NATIVE_FUNCTION_NAMES =
       new HashSet<>(
-          Arrays.stream(BuiltinFunction.values())
-              .map(BuiltinFunction::getFunctionName)
+          Arrays.stream(BuiltinScalarFunction.values())
+              .map(BuiltinScalarFunction::getFunctionName)
               .collect(Collectors.toList()));
 
   /**
@@ -56,15 +57,4 @@ public enum BuiltinFunction {
   public static Set<String> getNativeFunctionNames() {
     return NATIVE_FUNCTION_NAMES;
   }
-
-  // indicate whether the function is 'input one row, output one row'
-  public static boolean isMappable(String name) {
-    final String functionName = name.toLowerCase();
-    switch (functionName) {
-      case "diff":
-        return true;
-      default:
-        throw new IllegalArgumentException("Invalid BuiltInFunction: " + name);
-    }
-  }
 }
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinTimeSeriesGeneratingFunction.java b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinTimeSeriesGeneratingFunction.java
index f4561ef95c..c5e8c2767f 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinTimeSeriesGeneratingFunction.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinTimeSeriesGeneratingFunction.java
@@ -75,7 +75,6 @@ public enum BuiltinTimeSeriesGeneratingFunction {
   NON_NEGATIVE_DERIVATIVE("NON_NEGATIVE_DERIVATIVE", UDTFNonNegativeDerivative.class),
   TOP_K("TOP_K", UDTFTopK.class),
   BOTTOM_K("BOTTOM_K", UDTFBottomK.class),
-  CAST("CAST", UDTFCast.class),
   IN_RANGE("IN_RANGE", UDTFInRange.class),
   ON_OFF("ON_OFF", UDTFOnOff.class),
   ZERO_DURATION("ZERO_DURATION", UDTFZeroDuration.class),
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/UDTFCast.java b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/UDTFCast.java
deleted file mode 100644
index 6f5e8ad5e0..0000000000
--- a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/UDTFCast.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * 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.commons.udf.builtin;
-
-import org.apache.iotdb.commons.exception.MetadataException;
-import org.apache.iotdb.commons.udf.utils.UDFBinaryTransformer;
-import org.apache.iotdb.commons.udf.utils.UDFDataTypeTransformer;
-import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
-import org.apache.iotdb.tsfile.utils.Binary;
-import org.apache.iotdb.udf.api.UDTF;
-import org.apache.iotdb.udf.api.access.Row;
-import org.apache.iotdb.udf.api.collector.PointCollector;
-import org.apache.iotdb.udf.api.customizer.config.UDTFConfigurations;
-import org.apache.iotdb.udf.api.customizer.parameter.UDFParameterValidator;
-import org.apache.iotdb.udf.api.customizer.parameter.UDFParameters;
-import org.apache.iotdb.udf.api.customizer.strategy.RowByRowAccessStrategy;
-import org.apache.iotdb.udf.api.exception.UDFAttributeNotProvidedException;
-import org.apache.iotdb.udf.api.exception.UDFInputSeriesNumberNotValidException;
-
-import java.io.IOException;
-
-public class UDTFCast implements UDTF {
-
-  private TSDataType sourceDataType;
-  private TSDataType targetDataType;
-
-  @Override
-  public void validate(UDFParameterValidator validator)
-      throws UDFInputSeriesNumberNotValidException, UDFAttributeNotProvidedException {
-    validator.validateInputSeriesNumber(1).validateRequiredAttribute("type");
-  }
-
-  @Override
-  public void beforeStart(UDFParameters parameters, UDTFConfigurations configurations)
-      throws MetadataException {
-    sourceDataType = UDFDataTypeTransformer.transformToTsDataType(parameters.getDataType(0));
-    targetDataType = TSDataType.valueOf(parameters.getString("type"));
-
-    configurations
-        .setAccessStrategy(new RowByRowAccessStrategy())
-        .setOutputDataType(UDFDataTypeTransformer.transformToUDFDataType(targetDataType));
-  }
-
-  @Override
-  public void transform(Row row, PointCollector collector) throws IOException {
-    switch (sourceDataType) {
-      case INT32:
-        cast(row.getTime(), row.getInt(0), collector);
-        return;
-      case INT64:
-        cast(row.getTime(), row.getLong(0), collector);
-        return;
-      case FLOAT:
-        cast(row.getTime(), row.getFloat(0), collector);
-        return;
-      case DOUBLE:
-        cast(row.getTime(), row.getDouble(0), collector);
-        return;
-      case BOOLEAN:
-        cast(row.getTime(), row.getBoolean(0), collector);
-        return;
-      case TEXT:
-        cast(row.getTime(), UDFBinaryTransformer.transformToBinary(row.getBinary(0)), collector);
-        return;
-      default:
-        throw new UnsupportedOperationException();
-    }
-  }
-
-  private void cast(long time, int value, PointCollector collector) throws IOException {
-    switch (targetDataType) {
-      case INT32:
-        collector.putInt(time, value);
-        return;
-      case INT64:
-        collector.putLong(time, value);
-        return;
-      case FLOAT:
-        collector.putFloat(time, value);
-        return;
-      case DOUBLE:
-        collector.putDouble(time, value);
-        return;
-      case BOOLEAN:
-        collector.putBoolean(time, value != 0);
-        return;
-      case TEXT:
-        collector.putString(time, String.valueOf(value));
-        return;
-      default:
-        throw new UnsupportedOperationException();
-    }
-  }
-
-  private void cast(long time, long value, PointCollector collector) throws IOException {
-    switch (targetDataType) {
-      case INT32:
-        collector.putInt(time, (int) value);
-        return;
-      case INT64:
-        collector.putLong(time, value);
-        return;
-      case FLOAT:
-        collector.putFloat(time, value);
-        return;
-      case DOUBLE:
-        collector.putDouble(time, value);
-        return;
-      case BOOLEAN:
-        collector.putBoolean(time, value != 0L);
-        return;
-      case TEXT:
-        collector.putString(time, String.valueOf(value));
-        return;
-      default:
-        throw new UnsupportedOperationException();
-    }
-  }
-
-  private void cast(long time, float value, PointCollector collector) throws IOException {
-    switch (targetDataType) {
-      case INT32:
-        collector.putInt(time, (int) value);
-        return;
-      case INT64:
-        collector.putLong(time, (long) value);
-        return;
-      case FLOAT:
-        collector.putFloat(time, value);
-        return;
-      case DOUBLE:
-        collector.putDouble(time, value);
-        return;
-      case BOOLEAN:
-        collector.putBoolean(time, value != 0f);
-        return;
-      case TEXT:
-        collector.putString(time, String.valueOf(value));
-        return;
-      default:
-        throw new UnsupportedOperationException();
-    }
-  }
-
-  private void cast(long time, double value, PointCollector collector) throws IOException {
-    switch (targetDataType) {
-      case INT32:
-        collector.putInt(time, (int) value);
-        return;
-      case INT64:
-        collector.putLong(time, (long) value);
-        return;
-      case FLOAT:
-        collector.putFloat(time, (float) value);
-        return;
-      case DOUBLE:
-        collector.putDouble(time, value);
-        return;
-      case BOOLEAN:
-        collector.putBoolean(time, value != 0.0);
-        return;
-      case TEXT:
-        collector.putString(time, String.valueOf(value));
-        return;
-      default:
-        throw new UnsupportedOperationException();
-    }
-  }
-
-  private void cast(long time, boolean value, PointCollector collector) throws IOException {
-    switch (targetDataType) {
-      case INT32:
-        collector.putInt(time, value ? 1 : 0);
-        return;
-      case INT64:
-        collector.putLong(time, value ? 1L : 0L);
-        return;
-      case FLOAT:
-        collector.putFloat(time, value ? 1.0f : 0.0f);
-        return;
-      case DOUBLE:
-        collector.putDouble(time, value ? 1.0 : 0.0);
-        return;
-      case BOOLEAN:
-        collector.putBoolean(time, value);
-        return;
-      case TEXT:
-        collector.putString(time, String.valueOf(value));
-        return;
-      default:
-        throw new UnsupportedOperationException();
-    }
-  }
-
-  private void cast(long time, Binary value, PointCollector collector) throws IOException {
-    String stringValue = value.getStringValue();
-    switch (targetDataType) {
-      case INT32:
-        try {
-          collector.putInt(time, (int) Double.parseDouble(stringValue));
-        } catch (Exception ignored) {
-          // skip
-        }
-        return;
-      case INT64:
-        try {
-          collector.putLong(time, (long) Double.parseDouble(stringValue));
-        } catch (Exception ignored) {
-          // skip
-        }
-        return;
-      case FLOAT:
-        try {
-          collector.putFloat(time, (float) Double.parseDouble(stringValue));
-        } catch (Exception ignored) {
-          // skip
-        }
-        return;
-      case DOUBLE:
-        try {
-          collector.putDouble(time, Double.parseDouble(stringValue));
-        } catch (Exception ignored) {
-          // skip
-        }
-        return;
-      case BOOLEAN:
-        collector.putBoolean(time, !("false".equals(stringValue) || "".equals(stringValue)));
-        return;
-      case TEXT:
-        collector.putBinary(time, UDFBinaryTransformer.transformToUDFBinary(value));
-        return;
-      default:
-        throw new UnsupportedOperationException();
-    }
-  }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/constant/SqlConstant.java b/server/src/main/java/org/apache/iotdb/db/constant/SqlConstant.java
index d721244f50..3f9236b0f1 100644
--- a/server/src/main/java/org/apache/iotdb/db/constant/SqlConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/constant/SqlConstant.java
@@ -61,6 +61,9 @@ public class SqlConstant {
   public static final String LAST = "last";
   public static final String TIME_DURATION = "time_duration";
 
+  public static final String CAST_FUNCTION = "CAST";
+  public static final String CAST_TYPE = "type";
+
   public static String[] getSingleRootArray() {
     return SINGLE_ROOT_ARRAY;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionAnalyzer.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionAnalyzer.java
index bc713d84de..3a02bcb3a4 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionAnalyzer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionAnalyzer.java
@@ -23,7 +23,7 @@ import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTree;
-import org.apache.iotdb.commons.udf.builtin.BuiltinFunction;
+import org.apache.iotdb.commons.udf.builtin.BuiltinScalarFunction;
 import org.apache.iotdb.db.constant.SqlConstant;
 import org.apache.iotdb.db.exception.sql.SemanticException;
 import org.apache.iotdb.db.mpp.common.header.ColumnHeader;
@@ -699,8 +699,8 @@ public class ExpressionAnalyzer {
     } else if (expression instanceof UnaryExpression) {
       return isDeviceViewNeedSpecialProcess(((UnaryExpression) expression).getExpression());
     } else if (expression instanceof FunctionExpression) {
-      if (((FunctionExpression) expression).isBuiltInFunction()
-          && BuiltinFunction.DEVICE_VIEW_SPECIAL_PROCESS_FUNCTIONS.contains(
+      if (((FunctionExpression) expression).isBuiltInScalarFunction()
+          && BuiltinScalarFunction.DEVICE_VIEW_SPECIAL_PROCESS_FUNCTIONS.contains(
               ((FunctionExpression) expression).getFunctionName().toLowerCase())) {
         return true;
       }
@@ -733,7 +733,7 @@ public class ExpressionAnalyzer {
     } else if (expression instanceof FunctionExpression) {
       FunctionExpression functionExpression = (FunctionExpression) expression;
       if (!functionExpression.isMappable(analysis.getExpressionTypes())
-          || BuiltinFunction.DEVICE_VIEW_SPECIAL_PROCESS_FUNCTIONS.contains(
+          || BuiltinScalarFunction.DEVICE_VIEW_SPECIAL_PROCESS_FUNCTIONS.contains(
               functionExpression.getFunctionName())) {
         return false;
       }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionTypeAnalyzer.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionTypeAnalyzer.java
index 0a6ec4cfcc..28cf2d4b30 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionTypeAnalyzer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ExpressionTypeAnalyzer.java
@@ -256,12 +256,11 @@ public class ExpressionTypeAnalyzer {
                 functionExpression.getFunctionName(),
                 expressionTypes.get(NodeRef.of(inputExpressions.get(0)))));
       }
-      if (functionExpression.isBuiltInFunction()) {
+      if (functionExpression.isBuiltInScalarFunction()) {
         return setExpressionType(
             functionExpression,
-            TypeInferenceUtils.getBuiltInFunctionDataType(
-                functionExpression.getFunctionName(),
-                expressionTypes.get(NodeRef.of(inputExpressions.get(0)))));
+            TypeInferenceUtils.getBuiltInScalarFunctionDataType(
+                functionExpression, expressionTypes.get(NodeRef.of(inputExpressions.get(0)))));
       } else {
         return setExpressionType(
             functionExpression,
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/ShowFunctionsTask.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/ShowFunctionsTask.java
index b54183234f..96fa09fc3d 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/ShowFunctionsTask.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/ShowFunctionsTask.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.db.mpp.plan.execution.config.metadata;
 
 import org.apache.iotdb.commons.udf.UDFInformation;
 import org.apache.iotdb.commons.udf.builtin.BuiltinAggregationFunction;
+import org.apache.iotdb.commons.udf.builtin.BuiltinScalarFunction;
 import org.apache.iotdb.commons.udf.service.UDFManagementService;
 import org.apache.iotdb.db.mpp.common.header.ColumnHeader;
 import org.apache.iotdb.db.mpp.common.header.ColumnHeaderConstant;
@@ -44,6 +45,7 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import static org.apache.iotdb.commons.conf.IoTDBConstant.FUNCTION_TYPE_BUILTIN_SCALAR;
 import static org.apache.iotdb.commons.conf.IoTDBConstant.FUNCTION_TYPE_BUILTIN_UDAF;
 import static org.apache.iotdb.commons.conf.IoTDBConstant.FUNCTION_TYPE_BUILTIN_UDTF;
 import static org.apache.iotdb.commons.conf.IoTDBConstant.FUNCTION_TYPE_EXTERNAL_UDAF;
@@ -80,6 +82,7 @@ public class ShowFunctionsTask implements IConfigTask {
       appendUDFInformation(builder, udfInformation);
     }
     appendNativeFunctions(builder);
+    appendBuiltInScalarFunctions(builder);
     DatasetHeader datasetHeader = DatasetHeaderFactory.getShowFunctionsHeader();
     future.set(new ConfigTaskResult(TSStatusCode.SUCCESS_STATUS, builder.build(), datasetHeader));
   }
@@ -104,6 +107,18 @@ public class ShowFunctionsTask implements IConfigTask {
     }
   }
 
+  private static void appendBuiltInScalarFunctions(TsBlockBuilder builder) {
+    final Binary functionType = Binary.valueOf(FUNCTION_TYPE_BUILTIN_SCALAR);
+    final Binary className = Binary.valueOf("");
+    for (String functionName : BuiltinScalarFunction.getNativeFunctionNames()) {
+      builder.getTimeColumnBuilder().writeLong(0L);
+      builder.getColumnBuilder(0).writeBinary(Binary.valueOf(functionName.toUpperCase()));
+      builder.getColumnBuilder(1).writeBinary(functionType);
+      builder.getColumnBuilder(2).writeBinary(className);
+      builder.declarePosition();
+    }
+  }
+
   private static String getFunctionType(UDFInformation udfInformation) {
     String functionType = FUNCTION_TYPE_EXTERNAL_UDTF;
     try {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionExpression.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionExpression.java
index a9910fa941..1ca65fb373 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionExpression.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionExpression.java
@@ -22,7 +22,7 @@ package org.apache.iotdb.db.mpp.plan.expression.multi;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.udf.builtin.BuiltinAggregationFunction;
-import org.apache.iotdb.commons.udf.builtin.BuiltinFunction;
+import org.apache.iotdb.commons.udf.builtin.BuiltinScalarFunction;
 import org.apache.iotdb.db.mpp.common.NodeRef;
 import org.apache.iotdb.db.mpp.plan.expression.Expression;
 import org.apache.iotdb.db.mpp.plan.expression.ExpressionType;
@@ -48,6 +48,8 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.stream.Collectors;
 
+import static org.apache.iotdb.db.constant.SqlConstant.CAST_FUNCTION;
+
 public class FunctionExpression extends Expression {
 
   private FunctionType functionType;
@@ -102,8 +104,8 @@ public class FunctionExpression extends Expression {
     final String functionName = this.functionName.toLowerCase();
     if (BuiltinAggregationFunction.getNativeFunctionNames().contains(functionName)) {
       functionType = FunctionType.AGGREGATION_FUNCTION;
-    } else if (BuiltinFunction.getNativeFunctionNames().contains(functionName)) {
-      functionType = FunctionType.BUILT_IN_FUNCTION;
+    } else if (BuiltinScalarFunction.getNativeFunctionNames().contains(functionName)) {
+      functionType = FunctionType.BUILT_IN_SCALAR_FUNCTION;
     } else {
       functionType = FunctionType.UDF;
     }
@@ -117,11 +119,11 @@ public class FunctionExpression extends Expression {
     return functionType == FunctionType.AGGREGATION_FUNCTION;
   }
 
-  public Boolean isBuiltInFunction() {
+  public Boolean isBuiltInScalarFunction() {
     if (functionType == null) {
       initializeFunctionType();
     }
-    return functionType == FunctionType.BUILT_IN_FUNCTION;
+    return functionType == FunctionType.BUILT_IN_SCALAR_FUNCTION;
   }
 
   @Override
@@ -211,8 +213,7 @@ public class FunctionExpression extends Expression {
 
   @Override
   public boolean isMappable(Map<NodeRef<Expression>, TSDataType> expressionTypes) {
-    if (isBuiltInAggregationFunctionExpression()
-        || (isBuiltInFunction() && BuiltinFunction.isMappable(functionName))) {
+    if (isBuiltInAggregationFunctionExpression() || isBuiltInScalarFunction()) {
       return true;
     }
     return new UDTFInformationInferrer(functionName)
@@ -263,26 +264,35 @@ public class FunctionExpression extends Expression {
         }
       }
       if (!functionAttributes.isEmpty()) {
-        if (!expressions.isEmpty()) {
-          builder.append(", ");
-        }
-        Iterator<Entry<String, String>> iterator = functionAttributes.entrySet().iterator();
-        Entry<String, String> entry = iterator.next();
-        builder
-            .append("\"")
-            .append(entry.getKey())
-            .append("\"=\"")
-            .append(entry.getValue())
-            .append("\"");
-        while (iterator.hasNext()) {
-          entry = iterator.next();
+        // currently only the header of cast function is different
+        // this if-else branch can be extracted into a method if more new functions have different
+        // header
+        if (functionName.equalsIgnoreCase(CAST_FUNCTION)) {
+          // Cast has only one attribute
+          builder.append(" AS ");
+          builder.append(functionAttributes.entrySet().iterator().next().getValue());
+        } else {
+          if (!expressions.isEmpty()) {
+            builder.append(", ");
+          }
+          Iterator<Entry<String, String>> iterator = functionAttributes.entrySet().iterator();
+          Entry<String, String> entry = iterator.next();
           builder
-              .append(", ")
               .append("\"")
               .append(entry.getKey())
               .append("\"=\"")
               .append(entry.getValue())
               .append("\"");
+          while (iterator.hasNext()) {
+            entry = iterator.next();
+            builder
+                .append(", ")
+                .append("\"")
+                .append(entry.getKey())
+                .append("\"=\"")
+                .append(entry.getValue())
+                .append("\"");
+          }
         }
       }
       parametersString = builder.toString();
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
index 8d13d370a9..734ebb4bef 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
@@ -22,6 +22,6 @@ package org.apache.iotdb.db.mpp.plan.expression.multi;
 /** */
 public enum FunctionType {
   AGGREGATION_FUNCTION,
-  BUILT_IN_FUNCTION,
+  BUILT_IN_SCALAR_FUNCTION,
   UDF
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInFunctionHelper.java
similarity index 85%
copy from server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
copy to server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInFunctionHelper.java
index 8d13d370a9..aae87b85c1 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInFunctionHelper.java
@@ -17,11 +17,6 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.mpp.plan.expression.multi;
+package org.apache.iotdb.db.mpp.plan.expression.multi.builtin;
 
-/** */
-public enum FunctionType {
-  AGGREGATION_FUNCTION,
-  BUILT_IN_FUNCTION,
-  UDF
-}
+public interface BuiltInFunctionHelper {}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelper.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelper.java
new file mode 100644
index 0000000000..8966610e41
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelper.java
@@ -0,0 +1,74 @@
+/*
+ * 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.mpp.plan.expression.multi.builtin;
+
+import org.apache.iotdb.db.exception.sql.SemanticException;
+import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
+import org.apache.iotdb.db.mpp.transformation.api.LayerPointReader;
+import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.Transformer;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+/**
+ * This interface defines the methods that FunctionExpression may use if it is a FunctionExpression
+ * representing a built-in function
+ */
+public interface BuiltInScalarFunctionHelper extends BuiltInFunctionHelper {
+  /**
+   * Check if the input size is correct. For example, function DIFF only supports one column as
+   * input. Throw {@link SemanticException} if the input size is not correct.
+   */
+  void checkBuiltInScalarFunctionInputSize(FunctionExpression functionExpression)
+      throws SemanticException;
+
+  /**
+   * Check if the input TsDataType is correct. Throw {@link SemanticException} if the type is not
+   * correct.
+   *
+   * @param tsDataType TSDataType of input series.
+   */
+  void checkBuiltInScalarFunctionInputDataType(TSDataType tsDataType) throws SemanticException;
+
+  /**
+   * Return the type of data after input is processed by this scalar function.
+   *
+   * @return TsDataType
+   */
+  TSDataType getBuiltInScalarFunctionReturnType(FunctionExpression functionExpression);
+
+  /**
+   * @param expression The FunctionExpression representing the scalar function
+   * @param columnTransformer input ColumnTransformer
+   * @return Specific ColumnTransformer of this scalar function
+   */
+  ColumnTransformer getBuiltInScalarFunctionColumnTransformer(
+      FunctionExpression expression, ColumnTransformer columnTransformer);
+
+  /**
+   * Construct a {@link Transformer} for this built-in function in {@link
+   * org.apache.iotdb.db.mpp.plan.expression.visitor.IntermediateLayerVisitor}
+   *
+   * @param expression The FunctionExpression representing the scalar function
+   * @param layerPointReader input reader
+   * @return Specific Transformer of this scalar function
+   */
+  Transformer getBuiltInScalarFunctionTransformer(
+      FunctionExpression expression, LayerPointReader layerPointReader);
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelperFactory.java
similarity index 54%
copy from server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
copy to server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelperFactory.java
index 8d13d370a9..1454e5cca4 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/FunctionType.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelperFactory.java
@@ -17,11 +17,22 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.mpp.plan.expression.multi;
+package org.apache.iotdb.db.mpp.plan.expression.multi.builtin;
 
-/** */
-public enum FunctionType {
-  AGGREGATION_FUNCTION,
-  BUILT_IN_FUNCTION,
-  UDF
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.helper.CastHelper;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.helper.DiffHelper;
+
+public class BuiltInScalarFunctionHelperFactory {
+  public static BuiltInScalarFunctionHelper createHelper(String functionName) {
+    functionName = functionName.toUpperCase();
+    switch (functionName) {
+      case "DIFF":
+        return new DiffHelper();
+      case "CAST":
+        return new CastHelper();
+      default:
+        throw new IllegalArgumentException(
+            String.format("Invalid scalar function [%s].", functionName));
+    }
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/helper/CastHelper.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/helper/CastHelper.java
new file mode 100644
index 0000000000..39eb31ba5f
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/helper/CastHelper.java
@@ -0,0 +1,148 @@
+/*
+ * 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.mpp.plan.expression.multi.builtin.helper;
+
+import org.apache.iotdb.db.exception.sql.SemanticException;
+import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.BuiltInScalarFunctionHelper;
+import org.apache.iotdb.db.mpp.transformation.api.LayerPointReader;
+import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.column.unary.scalar.CastFunctionColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.Transformer;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.scalar.CastFunctionTransformer;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.read.common.type.TypeFactory;
+
+import static org.apache.iotdb.db.constant.SqlConstant.CAST_TYPE;
+import static org.apache.iotdb.db.mpp.plan.parser.ASTVisitor.checkFunctionExpressionInputSize;
+
+public class CastHelper implements BuiltInScalarFunctionHelper {
+  @Override
+  public void checkBuiltInScalarFunctionInputSize(FunctionExpression functionExpression)
+      throws SemanticException {
+    checkFunctionExpressionInputSize(
+        functionExpression.getExpressionString(), functionExpression.getExpressions().size(), 1);
+  }
+
+  @Override
+  public void checkBuiltInScalarFunctionInputDataType(TSDataType tsDataType)
+      throws SemanticException {}
+
+  @Override
+  public TSDataType getBuiltInScalarFunctionReturnType(FunctionExpression functionExpression) {
+    if (!functionExpression.getFunctionAttributes().containsKey(CAST_TYPE)) {
+      throw new SemanticException("Function Cast must specify a target data type.");
+    }
+    return TSDataType.valueOf(
+        functionExpression.getFunctionAttributes().get(CAST_TYPE).toUpperCase());
+  }
+
+  @Override
+  public ColumnTransformer getBuiltInScalarFunctionColumnTransformer(
+      FunctionExpression expression, ColumnTransformer columnTransformer) {
+    return new CastFunctionColumnTransformer(
+        TypeFactory.getType(this.getBuiltInScalarFunctionReturnType(expression)),
+        columnTransformer);
+  }
+
+  @Override
+  public Transformer getBuiltInScalarFunctionTransformer(
+      FunctionExpression expression, LayerPointReader layerPointReader) {
+    return new CastFunctionTransformer(
+        layerPointReader, this.getBuiltInScalarFunctionReturnType(expression));
+  }
+
+  public static int castLongToInt(long value) {
+    if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
+      throw new RuntimeException(
+          String.format("long value %d is out of range of integer value.", value));
+    }
+    return (int) value;
+  }
+
+  public static int castFloatToInt(float value) {
+    if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
+      throw new RuntimeException(
+          String.format("Float value %f is out of range of integer value.", value));
+    }
+    return Math.round(value);
+  }
+
+  public static long castFloatToLong(float value) {
+    if (value > Long.MAX_VALUE || value < Long.MIN_VALUE) {
+      throw new RuntimeException(
+          String.format("Float value %f is out of range of long value.", value));
+    }
+    return Math.round((double) value);
+  }
+
+  public static int castDoubleToInt(double value) {
+    if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
+      throw new RuntimeException(
+          String.format("Double value %f is out of range of integer value.", value));
+    }
+    return Math.round((float) value);
+  }
+
+  public static long castDoubleToLong(double value) {
+    if (value > Long.MAX_VALUE || value < Long.MIN_VALUE) {
+      throw new RuntimeException(
+          String.format("Double value %f is out of range of long value.", value));
+    }
+    return Math.round(value);
+  }
+
+  public static float castDoubleToFloat(double value) {
+    if (value > Float.MAX_VALUE || value < -Float.MAX_VALUE) {
+      throw new RuntimeException(
+          String.format("Double value %f is out of range of float value.", value));
+    }
+    return (float) value;
+  }
+
+  public static float castTextToFloat(String value) {
+    float f = Float.parseFloat(value);
+    if (f == Float.POSITIVE_INFINITY || f == Float.NEGATIVE_INFINITY) {
+      throw new RuntimeException(
+          String.format("Text value %s is out of range of float value.", value));
+    }
+    return f;
+  }
+
+  public static Double castTextToDouble(String value) {
+    double d = Double.parseDouble(value);
+    if (d == Double.POSITIVE_INFINITY || d == Double.NEGATIVE_INFINITY) {
+      throw new RuntimeException(
+          String.format("Text value %s is out of range of double value.", value));
+    }
+    return d;
+  }
+
+  public static boolean castTextToBoolean(String value) {
+    String lowerCase = value.toLowerCase();
+    if (lowerCase.equals("true")) {
+      return true;
+    } else if (lowerCase.equals("false")) {
+      return false;
+    } else {
+      throw new RuntimeException(String.format("Invalid text input for boolean type: %s", value));
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/helper/DiffHelper.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/helper/DiffHelper.java
new file mode 100644
index 0000000000..16c88a4205
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/helper/DiffHelper.java
@@ -0,0 +1,77 @@
+/*
+ * 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.mpp.plan.expression.multi.builtin.helper;
+
+import org.apache.iotdb.db.exception.sql.SemanticException;
+import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.BuiltInScalarFunctionHelper;
+import org.apache.iotdb.db.mpp.transformation.api.LayerPointReader;
+import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.column.unary.scalar.DiffFunctionColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.Transformer;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.scalar.DiffFunctionTransformer;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.read.common.type.TypeFactory;
+
+import static org.apache.iotdb.db.mpp.plan.parser.ASTVisitor.checkFunctionExpressionInputSize;
+
+public class DiffHelper implements BuiltInScalarFunctionHelper {
+
+  @Override
+  public void checkBuiltInScalarFunctionInputSize(FunctionExpression functionExpression)
+      throws SemanticException {
+    checkFunctionExpressionInputSize(
+        functionExpression.getExpressionString(), functionExpression.getExpressions().size(), 1);
+  }
+
+  @Override
+  public void checkBuiltInScalarFunctionInputDataType(TSDataType tsDataType)
+      throws SemanticException {
+    if (tsDataType.isNumeric()) {
+      return;
+    }
+    throw new SemanticException(
+        "Input series of Scalar function [DIFF] only supports numeric data types [INT32, INT64, FLOAT, DOUBLE]");
+  }
+
+  @Override
+  public TSDataType getBuiltInScalarFunctionReturnType(FunctionExpression functionExpression) {
+    return TSDataType.DOUBLE;
+  }
+
+  @Override
+  public ColumnTransformer getBuiltInScalarFunctionColumnTransformer(
+      FunctionExpression expression, ColumnTransformer columnTransformer) {
+    return new DiffFunctionColumnTransformer(
+        TypeFactory.getType(TSDataType.DOUBLE),
+        columnTransformer,
+        Boolean.parseBoolean(
+            expression.getFunctionAttributes().getOrDefault("ignoreNull", "true")));
+  }
+
+  @Override
+  public Transformer getBuiltInScalarFunctionTransformer(
+      FunctionExpression expression, LayerPointReader layerPointReader) {
+    return new DiffFunctionTransformer(
+        layerPointReader,
+        Boolean.parseBoolean(
+            expression.getFunctionAttributes().getOrDefault("ignoreNull", "true")));
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ColumnTransformerVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ColumnTransformerVisitor.java
index c980f79967..9352e2d358 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ColumnTransformerVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/ColumnTransformerVisitor.java
@@ -19,7 +19,6 @@
 
 package org.apache.iotdb.db.mpp.plan.expression.visitor;
 
-import org.apache.iotdb.db.constant.SqlConstant;
 import org.apache.iotdb.db.mpp.common.NodeRef;
 import org.apache.iotdb.db.mpp.plan.expression.Expression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.BinaryExpression;
@@ -28,6 +27,7 @@ import org.apache.iotdb.db.mpp.plan.expression.leaf.NullOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.BuiltInScalarFunctionHelperFactory;
 import org.apache.iotdb.db.mpp.plan.expression.ternary.BetweenExpression;
 import org.apache.iotdb.db.mpp.plan.expression.ternary.TernaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.unary.InExpression;
@@ -58,7 +58,6 @@ import org.apache.iotdb.db.mpp.transformation.dag.column.leaf.TimeColumnTransfor
 import org.apache.iotdb.db.mpp.transformation.dag.column.multi.MappableUDFColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.ternary.BetweenColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.unary.ArithmeticNegationColumnTransformer;
-import org.apache.iotdb.db.mpp.transformation.dag.column.unary.DiffFunctionColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.unary.InColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.unary.IsNullColumnTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.column.unary.LogicNotColumnTransformer;
@@ -220,9 +219,9 @@ public class ColumnTransformerVisitor
                       .getValueColumnIndex());
           context.leafList.add(identity);
           context.cache.put(functionExpression, identity);
-        } else if (functionExpression.isBuiltInFunction()) {
+        } else if (functionExpression.isBuiltInScalarFunction()) {
           context.cache.put(
-              functionExpression, getBuiltInFunctionTransformer(functionExpression, context));
+              functionExpression, getBuiltInScalarFunctionTransformer(functionExpression, context));
         } else {
           ColumnTransformer[] inputColumnTransformers =
               expressions.stream()
@@ -259,22 +258,12 @@ public class ColumnTransformerVisitor
     return res;
   }
 
-  private ColumnTransformer getBuiltInFunctionTransformer(
+  private ColumnTransformer getBuiltInScalarFunctionTransformer(
       FunctionExpression expression, ColumnTransformerVisitorContext context) {
     ColumnTransformer childColumnTransformer =
         this.process(expression.getExpressions().get(0), context);
-
-    switch (expression.getFunctionName()) {
-      case SqlConstant.DIFF:
-        return new DiffFunctionColumnTransformer(
-            TypeFactory.getType(TSDataType.DOUBLE),
-            childColumnTransformer,
-            Boolean.parseBoolean(
-                expression.getFunctionAttributes().getOrDefault("ignoreNull", "true")));
-      default:
-        throw new IllegalArgumentException(
-            "Invalid Scalar function: " + expression.getExpressionString());
-    }
+    return BuiltInScalarFunctionHelperFactory.createHelper(expression.getFunctionName())
+        .getBuiltInScalarFunctionColumnTransformer(expression, childColumnTransformer);
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/IntermediateLayerVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/IntermediateLayerVisitor.java
index 68681dfac7..9f481e4a1d 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/IntermediateLayerVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/visitor/IntermediateLayerVisitor.java
@@ -19,7 +19,6 @@
 
 package org.apache.iotdb.db.mpp.plan.expression.visitor;
 
-import org.apache.iotdb.db.constant.SqlConstant;
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.mpp.common.NodeRef;
 import org.apache.iotdb.db.mpp.plan.expression.Expression;
@@ -28,6 +27,7 @@ import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.BuiltInScalarFunctionHelperFactory;
 import org.apache.iotdb.db.mpp.plan.expression.ternary.BetweenExpression;
 import org.apache.iotdb.db.mpp.plan.expression.ternary.TernaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.unary.InExpression;
@@ -63,7 +63,6 @@ import org.apache.iotdb.db.mpp.transformation.dag.transformer.multi.UDFQueryRowW
 import org.apache.iotdb.db.mpp.transformation.dag.transformer.multi.UDFQueryTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.transformer.ternary.BetweenTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.ArithmeticNegationTransformer;
-import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.DiffFunctionTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.InTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.IsNullTransformer;
 import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.LogicNotTransformer;
@@ -200,8 +199,8 @@ public class IntermediateLayerVisitor
             new TransparentTransformer(
                 context.rawTimeSeriesInputLayer.constructValuePointReader(
                     functionExpression.getInputColumnIndex()));
-      } else if (functionExpression.isBuiltInFunction()) {
-        transformer = getBuiltInFunctionTransformer(functionExpression, context);
+      } else if (functionExpression.isBuiltInScalarFunction()) {
+        transformer = getBuiltInScalarFunctionTransformer(functionExpression, context);
       } else {
         try {
           IntermediateLayer udfInputIntermediateLayer =
@@ -223,22 +222,13 @@ public class IntermediateLayerVisitor
     return context.expressionIntermediateLayerMap.get(functionExpression);
   }
 
-  private Transformer getBuiltInFunctionTransformer(
+  private Transformer getBuiltInScalarFunctionTransformer(
       FunctionExpression expression, IntermediateLayerVisitorContext context) {
 
     LayerPointReader childPointReader =
         this.process(expression.getExpressions().get(0), context).constructPointReader();
-
-    switch (expression.getFunctionName()) {
-      case SqlConstant.DIFF:
-        return new DiffFunctionTransformer(
-            childPointReader,
-            Boolean.parseBoolean(
-                expression.getFunctionAttributes().getOrDefault("ignoreNull", "true")));
-      default:
-        throw new IllegalArgumentException(
-            "Invalid Scalar function: " + expression.getExpressionString());
-    }
+    return BuiltInScalarFunctionHelperFactory.createHelper(expression.getFunctionName())
+        .getBuiltInScalarFunctionTransformer(expression, childPointReader);
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 07aa25ef6e..65f31a2945 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -57,6 +57,7 @@ import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.BuiltInScalarFunctionHelperFactory;
 import org.apache.iotdb.db.mpp.plan.expression.ternary.BetweenExpression;
 import org.apache.iotdb.db.mpp.plan.expression.unary.InExpression;
 import org.apache.iotdb.db.mpp.plan.expression.unary.IsNullExpression;
@@ -206,6 +207,8 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import static org.apache.iotdb.db.constant.SqlConstant.CAST_FUNCTION;
+import static org.apache.iotdb.db.constant.SqlConstant.CAST_TYPE;
 import static org.apache.iotdb.db.metadata.MetadataConstant.ALL_RESULT_NODES;
 
 /** Parse AST to Statement. */
@@ -224,7 +227,6 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
       "Only one of group by time or group by variation/series/session can be supported at a time";
 
   private static final String IGNORENULL = "IgnoreNull";
-
   private ZoneId zoneId;
 
   public void setZoneId(ZoneId zoneId) {
@@ -2314,6 +2316,10 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
       return parseInExpression(context, canUseFullPath);
     }
 
+    if (context.castInput != null) {
+      return parseCastFunction(context, canUseFullPath);
+    }
+
     if (context.functionName() != null) {
       return parseFunctionExpression(context, canUseFullPath);
     }
@@ -2334,6 +2340,14 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     throw new UnsupportedOperationException();
   }
 
+  private Expression parseCastFunction(
+      IoTDBSqlParser.ExpressionContext castClause, boolean canUseFullPath) {
+    FunctionExpression functionExpression = new FunctionExpression(CAST_FUNCTION);
+    functionExpression.addExpression(parseExpression(castClause.castInput, canUseFullPath));
+    functionExpression.addAttribute(CAST_TYPE, parseAttributeValue(castClause.attributeValue()));
+    return functionExpression;
+  }
+
   private Expression parseFunctionExpression(
       IoTDBSqlParser.ExpressionContext functionClause, boolean canUseFullPath) {
     FunctionExpression functionExpression =
@@ -2379,8 +2393,8 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     // type check of input expressions is put in ExpressionTypeAnalyzer
     if (functionExpression.isBuiltInAggregationFunctionExpression()) {
       checkAggregationFunctionInput(functionExpression);
-    } else if (functionExpression.isBuiltInFunction()) {
-      checkBuiltInFunctionInput(functionExpression);
+    } else if (functionExpression.isBuiltInScalarFunction()) {
+      checkBuiltInScalarFunctionInput(functionExpression);
     }
     return functionExpression;
   }
@@ -2416,22 +2430,12 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
     }
   }
 
-  private void checkBuiltInFunctionInput(FunctionExpression functionExpression) {
-    final String functionName = functionExpression.getFunctionName().toLowerCase();
-    switch (functionName) {
-      case SqlConstant.DIFF:
-        checkFunctionExpressionInputSize(
-            functionExpression.getExpressionString(),
-            functionExpression.getExpressions().size(),
-            1);
-        return;
-      default:
-        throw new IllegalArgumentException(
-            "Invalid BuiltInFunction: " + functionExpression.getFunctionName());
-    }
+  private void checkBuiltInScalarFunctionInput(FunctionExpression functionExpression) {
+    BuiltInScalarFunctionHelperFactory.createHelper(functionExpression.getFunctionName())
+        .checkBuiltInScalarFunctionInputSize(functionExpression);
   }
 
-  private void checkFunctionExpressionInputSize(
+  public static void checkFunctionExpressionInputSize(
       String expressionString, int actual, int... expected) {
     for (int expect : expected) {
       if (expect == actual) {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/CastFunctionColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/CastFunctionColumnTransformer.java
new file mode 100644
index 0000000000..ac761db756
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/CastFunctionColumnTransformer.java
@@ -0,0 +1,230 @@
+/*
+ * 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.mpp.transformation.dag.column.unary.scalar;
+
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.helper.CastHelper;
+import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.column.unary.UnaryColumnTransformer;
+import org.apache.iotdb.tsfile.read.common.block.column.Column;
+import org.apache.iotdb.tsfile.read.common.block.column.ColumnBuilder;
+import org.apache.iotdb.tsfile.read.common.type.Type;
+import org.apache.iotdb.tsfile.read.common.type.TypeEnum;
+import org.apache.iotdb.tsfile.utils.Binary;
+
+public class CastFunctionColumnTransformer extends UnaryColumnTransformer {
+
+  public CastFunctionColumnTransformer(Type returnType, ColumnTransformer childColumnTransformer) {
+    super(returnType, childColumnTransformer);
+  }
+
+  @Override
+  protected void doTransform(Column column, ColumnBuilder columnBuilder) {
+    TypeEnum sourceType = childColumnTransformer.getType().getTypeEnum();
+    Type childType = childColumnTransformer.getType();
+    for (int i = 0, n = column.getPositionCount(); i < n; i++) {
+      if (!column.isNull(i)) {
+        switch (sourceType) {
+          case INT32:
+            cast(columnBuilder, childType.getInt(column, i));
+            break;
+          case INT64:
+            cast(columnBuilder, childType.getLong(column, i));
+            break;
+          case FLOAT:
+            cast(columnBuilder, childType.getFloat(column, i));
+            break;
+          case DOUBLE:
+            cast(columnBuilder, childType.getDouble(column, i));
+            break;
+          case BOOLEAN:
+            cast(columnBuilder, childType.getBoolean(column, i));
+            break;
+          case BINARY:
+            cast(columnBuilder, childType.getBinary(column, i));
+            break;
+          default:
+            throw new UnsupportedOperationException(
+                String.format(
+                    "Unsupported source dataType: %s",
+                    childColumnTransformer.getType().getTypeEnum()));
+        }
+      } else {
+        columnBuilder.appendNull();
+      }
+    }
+  }
+
+  private void cast(ColumnBuilder columnBuilder, int value) {
+    switch (returnType.getTypeEnum()) {
+      case INT32:
+        returnType.writeInt(columnBuilder, value);
+        break;
+      case INT64:
+        returnType.writeLong(columnBuilder, value);
+        break;
+      case FLOAT:
+        returnType.writeFloat(columnBuilder, value);
+        break;
+      case DOUBLE:
+        returnType.writeDouble(columnBuilder, value);
+        break;
+      case BOOLEAN:
+        returnType.writeBoolean(columnBuilder, value != 0);
+        break;
+      case BINARY:
+        returnType.writeBinary(columnBuilder, Binary.valueOf(String.valueOf(value)));
+        break;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", returnType.getTypeEnum()));
+    }
+  }
+
+  private void cast(ColumnBuilder columnBuilder, long value) {
+    switch (returnType.getTypeEnum()) {
+      case INT32:
+        returnType.writeInt(columnBuilder, (CastHelper.castLongToInt(value)));
+        break;
+      case INT64:
+        returnType.writeLong(columnBuilder, value);
+        break;
+      case FLOAT:
+        returnType.writeFloat(columnBuilder, value);
+        break;
+      case DOUBLE:
+        returnType.writeDouble(columnBuilder, value);
+        break;
+      case BOOLEAN:
+        returnType.writeBoolean(columnBuilder, value != 0L);
+        break;
+      case BINARY:
+        returnType.writeBinary(columnBuilder, Binary.valueOf(String.valueOf(value)));
+        break;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", returnType.getTypeEnum()));
+    }
+  }
+
+  private void cast(ColumnBuilder columnBuilder, float value) {
+    switch (returnType.getTypeEnum()) {
+      case INT32:
+        returnType.writeInt(columnBuilder, CastHelper.castFloatToInt(value));
+        break;
+      case INT64:
+        returnType.writeLong(columnBuilder, CastHelper.castFloatToLong(value));
+        break;
+      case FLOAT:
+        returnType.writeFloat(columnBuilder, value);
+        break;
+      case DOUBLE:
+        returnType.writeDouble(columnBuilder, value);
+        break;
+      case BOOLEAN:
+        returnType.writeBoolean(columnBuilder, value != 0.0f);
+        break;
+      case BINARY:
+        returnType.writeBinary(columnBuilder, Binary.valueOf(String.valueOf(value)));
+        break;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", returnType.getTypeEnum()));
+    }
+  }
+
+  private void cast(ColumnBuilder columnBuilder, double value) {
+    switch (returnType.getTypeEnum()) {
+      case INT32:
+        returnType.writeInt(columnBuilder, CastHelper.castDoubleToInt(value));
+        break;
+      case INT64:
+        returnType.writeLong(columnBuilder, CastHelper.castDoubleToLong(value));
+        break;
+      case FLOAT:
+        returnType.writeFloat(columnBuilder, CastHelper.castDoubleToFloat(value));
+        break;
+      case DOUBLE:
+        returnType.writeDouble(columnBuilder, value);
+        break;
+      case BOOLEAN:
+        returnType.writeBoolean(columnBuilder, value != 0.0);
+        break;
+      case BINARY:
+        returnType.writeBinary(columnBuilder, Binary.valueOf(String.valueOf(value)));
+        break;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", returnType.getTypeEnum()));
+    }
+  }
+
+  private void cast(ColumnBuilder columnBuilder, boolean value) {
+    switch (returnType.getTypeEnum()) {
+      case INT32:
+        returnType.writeInt(columnBuilder, value ? 1 : 0);
+        break;
+      case INT64:
+        returnType.writeLong(columnBuilder, value ? 1L : 0);
+        break;
+      case FLOAT:
+        returnType.writeFloat(columnBuilder, value ? 1.0f : 0);
+        break;
+      case DOUBLE:
+        returnType.writeDouble(columnBuilder, value ? 1.0 : 0);
+        break;
+      case BOOLEAN:
+        returnType.writeBoolean(columnBuilder, value);
+        break;
+      case BINARY:
+        returnType.writeBinary(columnBuilder, Binary.valueOf(String.valueOf(value)));
+        break;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", returnType.getTypeEnum()));
+    }
+  }
+
+  private void cast(ColumnBuilder columnBuilder, Binary value) {
+    String stringValue = value.getStringValue();
+    switch (returnType.getTypeEnum()) {
+      case INT32:
+        returnType.writeInt(columnBuilder, Integer.parseInt(stringValue));
+        break;
+      case INT64:
+        returnType.writeLong(columnBuilder, Long.parseLong(stringValue));
+        break;
+      case FLOAT:
+        returnType.writeFloat(columnBuilder, CastHelper.castTextToFloat(stringValue));
+        break;
+      case DOUBLE:
+        returnType.writeDouble(columnBuilder, CastHelper.castTextToDouble(stringValue));
+        break;
+      case BOOLEAN:
+        returnType.writeBoolean(columnBuilder, CastHelper.castTextToBoolean(stringValue));
+        break;
+      case BINARY:
+        returnType.writeBinary(columnBuilder, value);
+        break;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", returnType.getTypeEnum()));
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/DiffFunctionColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/DiffFunctionColumnTransformer.java
similarity index 93%
rename from server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/DiffFunctionColumnTransformer.java
rename to server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/DiffFunctionColumnTransformer.java
index 2128c5cd6c..954b7a5b4c 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/DiffFunctionColumnTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/DiffFunctionColumnTransformer.java
@@ -17,9 +17,10 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.mpp.transformation.dag.column.unary;
+package org.apache.iotdb.db.mpp.transformation.dag.column.unary.scalar;
 
 import org.apache.iotdb.db.mpp.transformation.dag.column.ColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.column.unary.UnaryColumnTransformer;
 import org.apache.iotdb.tsfile.read.common.block.column.Column;
 import org.apache.iotdb.tsfile.read.common.block.column.ColumnBuilder;
 import org.apache.iotdb.tsfile.read.common.type.Type;
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/CastFunctionTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/CastFunctionTransformer.java
new file mode 100644
index 0000000000..3b615d2e4c
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/CastFunctionTransformer.java
@@ -0,0 +1,228 @@
+/*
+ * 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.mpp.transformation.dag.transformer.unary.scalar;
+
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.helper.CastHelper;
+import org.apache.iotdb.db.mpp.transformation.api.LayerPointReader;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.UnaryTransformer;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.utils.Binary;
+
+import java.io.IOException;
+
+public class CastFunctionTransformer extends UnaryTransformer {
+  private final TSDataType targetDataType;
+
+  public CastFunctionTransformer(LayerPointReader layerPointReader, TSDataType targetDataType) {
+    super(layerPointReader);
+    this.targetDataType = targetDataType;
+  }
+
+  @Override
+  public TSDataType getDataType() {
+    return targetDataType;
+  }
+
+  @Override
+  protected void transformAndCache() throws QueryProcessException, IOException {
+    switch (layerPointReaderDataType) {
+      case INT32:
+        cast(layerPointReader.currentInt());
+        return;
+      case INT64:
+        cast(layerPointReader.currentLong());
+        return;
+      case FLOAT:
+        cast(layerPointReader.currentFloat());
+        return;
+      case DOUBLE:
+        cast(layerPointReader.currentDouble());
+        return;
+      case BOOLEAN:
+        cast(layerPointReader.currentBoolean());
+        return;
+      case TEXT:
+        cast(layerPointReader.currentBinary());
+        return;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported source dataType: %s", layerPointReaderDataType));
+    }
+  }
+
+  private void cast(int value) {
+    switch (targetDataType) {
+      case INT32:
+        cachedInt = value;
+        return;
+      case INT64:
+        cachedLong = value;
+        return;
+      case FLOAT:
+        cachedFloat = value;
+        return;
+      case DOUBLE:
+        cachedDouble = value;
+        return;
+      case BOOLEAN:
+        cachedBoolean = (value != 0);
+        return;
+      case TEXT:
+        cachedBinary = Binary.valueOf(String.valueOf(value));
+        return;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", layerPointReaderDataType));
+    }
+  }
+
+  private void cast(long value) {
+    switch (targetDataType) {
+      case INT32:
+        cachedInt = CastHelper.castLongToInt(value);
+        return;
+      case INT64:
+        cachedLong = value;
+        return;
+      case FLOAT:
+        cachedFloat = value;
+        return;
+      case DOUBLE:
+        cachedDouble = value;
+        return;
+      case BOOLEAN:
+        cachedBoolean = (value != 0L);
+        return;
+      case TEXT:
+        cachedBinary = Binary.valueOf(String.valueOf(value));
+        return;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", layerPointReaderDataType));
+    }
+  }
+
+  private void cast(float value) {
+    switch (targetDataType) {
+      case INT32:
+        cachedInt = CastHelper.castFloatToInt(value);
+        return;
+      case INT64:
+        cachedLong = CastHelper.castFloatToLong(value);
+        return;
+      case FLOAT:
+        cachedFloat = value;
+        return;
+      case DOUBLE:
+        cachedDouble = value;
+        return;
+      case BOOLEAN:
+        cachedBoolean = (value != 0f);
+        return;
+      case TEXT:
+        cachedBinary = Binary.valueOf(String.valueOf(value));
+        return;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", layerPointReaderDataType));
+    }
+  }
+
+  private void cast(double value) {
+    switch (targetDataType) {
+      case INT32:
+        cachedInt = CastHelper.castDoubleToInt(value);
+        return;
+      case INT64:
+        cachedLong = CastHelper.castDoubleToLong(value);
+        return;
+      case FLOAT:
+        cachedFloat = CastHelper.castDoubleToFloat(value);
+        return;
+      case DOUBLE:
+        cachedDouble = value;
+        return;
+      case BOOLEAN:
+        cachedBoolean = (value != 0.0);
+        return;
+      case TEXT:
+        cachedBinary = Binary.valueOf(String.valueOf(value));
+        return;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", layerPointReaderDataType));
+    }
+  }
+
+  private void cast(boolean value) {
+    switch (targetDataType) {
+      case INT32:
+        cachedInt = value ? 1 : 0;
+        return;
+      case INT64:
+        cachedLong = value ? 1L : 0;
+        return;
+      case FLOAT:
+        cachedFloat = value ? 1.0f : 0;
+        return;
+      case DOUBLE:
+        cachedDouble = value ? 1.0 : 0;
+        return;
+      case BOOLEAN:
+        cachedBoolean = value;
+        return;
+      case TEXT:
+        cachedBinary = Binary.valueOf(String.valueOf(value));
+        return;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", layerPointReaderDataType));
+    }
+  }
+
+  private void cast(Binary value) {
+    String stringValue = value.getStringValue();
+    // could throw exception when parsing string value
+    switch (targetDataType) {
+      case INT32:
+        cachedInt = Integer.parseInt(stringValue);
+        return;
+      case INT64:
+        cachedLong = Long.parseLong(stringValue);
+        return;
+      case FLOAT:
+        cachedFloat = CastHelper.castTextToFloat(stringValue);
+        return;
+      case DOUBLE:
+        cachedDouble = CastHelper.castTextToDouble(stringValue);
+        return;
+      case BOOLEAN:
+        cachedBoolean = CastHelper.castTextToBoolean(stringValue);
+        return;
+      case TEXT:
+        cachedBinary = Binary.valueOf(String.valueOf(value));
+        return;
+      default:
+        throw new UnsupportedOperationException(
+            String.format("Unsupported target dataType: %s", layerPointReaderDataType));
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/DiffFunctionTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/DiffFunctionTransformer.java
similarity index 97%
rename from server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/DiffFunctionTransformer.java
rename to server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/DiffFunctionTransformer.java
index 8ed9b02c9d..476b71b4c6 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/DiffFunctionTransformer.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/DiffFunctionTransformer.java
@@ -17,11 +17,12 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.mpp.transformation.dag.transformer.unary;
+package org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.scalar;
 
 import org.apache.iotdb.db.exception.query.QueryProcessException;
 import org.apache.iotdb.db.mpp.transformation.api.LayerPointReader;
 import org.apache.iotdb.db.mpp.transformation.api.YieldableState;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.UnaryTransformer;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
 import java.io.IOException;
diff --git a/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java b/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
index e655f9b158..36d1a076af 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java
@@ -28,6 +28,9 @@ import org.apache.iotdb.db.mpp.plan.expression.Expression;
 import org.apache.iotdb.db.mpp.plan.expression.binary.CompareBinaryExpression;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
+import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.BuiltInScalarFunctionHelper;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.BuiltInScalarFunctionHelperFactory;
 import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 
@@ -244,37 +247,19 @@ public class TypeInferenceUtils {
     }
   }
 
-  public static TSDataType getBuiltInFunctionDataType(String funcName, TSDataType dataType) {
-    if (funcName == null) {
-      throw new IllegalArgumentException("ScalarFunction Name must not be null");
+  public static TSDataType getBuiltInScalarFunctionDataType(
+      FunctionExpression functionExpression, TSDataType dataType) {
+    String functionName = functionExpression.getFunctionName();
+    if (functionName == null) {
+      throw new IllegalArgumentException("ScalarFunction Name must not be null.");
     }
-    verifyIsBuiltInFunctionDataTypeMatched(funcName, dataType);
-
-    switch (funcName.toLowerCase()) {
-      case SqlConstant.DIFF:
-        return TSDataType.DOUBLE;
-      default:
-        throw new IllegalArgumentException("Invalid Scalar function: " + funcName);
-    }
-  }
-
-  private static void verifyIsBuiltInFunctionDataTypeMatched(String funcName, TSDataType dataType) {
-    // input is NullOperand, needn't check
-    if (dataType == null) {
-      return;
-    }
-    switch (funcName.toLowerCase()) {
-      case SqlConstant.DIFF:
-        if (dataType.isNumeric()) {
-          return;
-        }
-        throw new SemanticException(
-            String.format(
-                "Input series of Scalar function [%s] only supports numeric data types [INT32, INT64, FLOAT, DOUBLE]",
-                funcName));
-      default:
-        throw new IllegalArgumentException("Invalid Scalar function: " + funcName);
+    BuiltInScalarFunctionHelper helper =
+        BuiltInScalarFunctionHelperFactory.createHelper(functionName);
+    // check input data type first if it is not a NullOperand
+    if (dataType != null) {
+      helper.checkBuiltInScalarFunctionInputDataType(dataType);
     }
+    return helper.getBuiltInScalarFunctionReturnType(functionExpression);
   }
 
   public static boolean canAutoCast(TSDataType fromType, TSDataType toType) {