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/16 10:29:30 UTC
[iotdb] branch master updated: [IoTDB-5636] Add round as built-in scalar 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 53d06b296b [IoTDB-5636] Add round as built-in scalar function
53d06b296b is described below
commit 53d06b296b272902de1194e2c6856220665a5f01
Author: Zhijia Cao <ca...@126.com>
AuthorDate: Thu Mar 16 18:29:21 2023 +0800
[IoTDB-5636] Add round as built-in scalar 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/Mathematical.md | 65 ++--
.../UserGuide/Operators-Functions/Mathematical.md | 63 ++--
docs/zh/UserGuide/Operators-Functions/Overview.md | 44 +--
.../itbase/constant/BuiltinScalarFunctionEnum.java | 1 +
.../BuiltinTimeSeriesGeneratingFunctionEnum.java | 1 -
.../scalar/IoTDBRoundFunctionIT.java | 327 +++++++++++++++++++++
.../commons/udf/builtin/BuiltinScalarFunction.java | 1 +
.../BuiltinTimeSeriesGeneratingFunction.java | 1 -
.../iotdb/commons/udf/builtin/UDTFRound.java | 28 --
.../org/apache/iotdb/db/constant/SqlConstant.java | 2 +
.../plan/expression/multi/FunctionExpression.java | 2 +-
.../multi/builtin/BuiltInScalarFunctionHelper.java | 4 +-
.../BuiltInScalarFunctionHelperFactory.java | 3 +
.../multi/builtin/helper/RoundFunctionHelper.java | 84 ++++++
.../iotdb/db/mpp/plan/parser/ASTVisitor.java | 14 +
.../scalar/RoundFunctionColumnTransformer.java | 72 +++++
.../unary/scalar/RoundFunctionTransformer.java | 72 +++++
20 files changed, 691 insertions(+), 99 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 3ebcd8f92d..ce0b227f43 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
@@ -156,6 +156,7 @@ keyWords
| REPLACE
| REVOKE
| ROLE
+ | ROUND
| RUNNING
| SCHEMA
| SELECT
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 b5173fe252..e7a8e8b603 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
@@ -983,6 +983,7 @@ functionName
scalarFunctionExpression
: CAST LR_BRACKET castInput=expression AS attributeValue RR_BRACKET
| REPLACE LR_BRACKET text=expression COMMA from=STRING_LITERAL COMMA to=STRING_LITERAL RR_BRACKET
+ | ROUND LR_BRACKET input=expression (COMMA places=constant)? RR_BRACKET
;
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 3791743780..9e5bfcf417 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
@@ -570,6 +570,10 @@ ROOT
: R O O T
;
+ROUND
+ : R O U N D
+ ;
+
RUNNING
: R U N N I N G
;
diff --git a/docs/UserGuide/Operators-Functions/Mathematical.md b/docs/UserGuide/Operators-Functions/Mathematical.md
index f477e58c83..c5e2146404 100644
--- a/docs/UserGuide/Operators-Functions/Mathematical.md
+++ b/docs/UserGuide/Operators-Functions/Mathematical.md
@@ -67,28 +67,28 @@ It costs 0.014s
Currently, IoTDB supports the following mathematical functions. The behavior of these mathematical functions is consistent with the behavior of these functions in the Java Math standard library.
-| Function Name | Allowed Input Series Data Types | Output Series Data Type | Corresponding Implementation in the Java Standard Library |
-| ------------- | ------------------------------- | ----------------------------- | ------------------------------------------------------------ |
-| SIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sin(double) |
-| COS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#cos(double) |
-| TAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#tan(double) |
-| ASIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#asin(double) |
-| ACOS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#acos(double) |
-| ATAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#atan(double) |
-| SINH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sinh(double) |
-| COSH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#cosh(double) |
-| TANH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#tanh(double) |
-| DEGREES | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#toDegrees(double) |
-| RADIANS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#toRadians(double) |
-| ABS | INT32 / INT64 / FLOAT / DOUBLE | Same type as the input series | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
-| SIGN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#signum(double) |
-| CEIL | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#ceil(double) |
-| FLOOR | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#floor(double) |
-| ROUND | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#rint(double) |
-| EXP | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#exp(double) |
-| LN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#log(double) |
-| LOG10 | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#log10(double) |
-| SQRT | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sqrt(double) |
+| Function Name | Allowed Input Series Data Types | Output Series Data Type |Necessary attribute parameter | Corresponding Implementation in the Java Standard Library |
+| ------------- | ------------------------------- | ----------------------------- |-----| ------------------------------------------------------------ |
+| SIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sin(double) |
+| COS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#cos(double) |
+| TAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#tan(double) |
+| ASIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#asin(double) |
+| ACOS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#acos(double) |
+| ATAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#atan(double) |
+| SINH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sinh(double) |
+| COSH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#cosh(double) |
+| TANH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#tanh(double) |
+| DEGREES | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#toDegrees(double) |
+| RADIANS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#toRadians(double) |
+| ABS | INT32 / INT64 / FLOAT / DOUBLE | Same type as the input series | | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
+| SIGN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#signum(double) |
+| CEIL | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#ceil(double) |
+| FLOOR | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#floor(double) |
+| ROUND | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE |'places' : Round the significant number, positive number is the significant number after the decimal point, negative number is the significant number of whole number | Math#rint(Math#pow(10,places))/Math#pow(10,places) |
+| EXP | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#exp(double) |
+| LN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#log(double) |
+| LOG10 | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#log10(double) |
+| SQRT | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sqrt(double) |
Example:
@@ -110,4 +110,25 @@ Result:
+-----------------------------+-------------------+-------------------+--------------------+-------------------+
Total line number = 5
It costs 0.008s
+```
+
+### ROUND
+Example:
+```sql
+select s4,round(s4),round(s4,2),round(s4,-1) from root.sg1.d1
+```
+
+```sql
++-----------------------------+-------------+--------------------+----------------------+-----------------------+
+| Time|root.db.d1.s4|ROUND(root.db.d1.s4)|ROUND(root.db.d1.s4,2)|ROUND(root.db.d1.s4,-1)|
++-----------------------------+-------------+--------------------+----------------------+-----------------------+
+|1970-01-01T08:00:00.001+08:00| 101.14345| 101.0| 101.14| 100.0|
+|1970-01-01T08:00:00.002+08:00| 20.144346| 20.0| 20.14| 20.0|
+|1970-01-01T08:00:00.003+08:00| 20.614372| 21.0| 20.61| 20.0|
+|1970-01-01T08:00:00.005+08:00| 20.814346| 21.0| 20.81| 20.0|
+|1970-01-01T08:00:00.006+08:00| 60.71443| 61.0| 60.71| 60.0|
+|2023-03-13T16:16:19.764+08:00| 10.143425| 10.0| 10.14| 10.0|
++-----------------------------+-------------+--------------------+----------------------+-----------------------+
+Total line number = 6
+It costs 0.059s
```
\ No newline at end of file
diff --git a/docs/zh/UserGuide/Operators-Functions/Mathematical.md b/docs/zh/UserGuide/Operators-Functions/Mathematical.md
index 9d96c440e6..3b5cf35c6c 100644
--- a/docs/zh/UserGuide/Operators-Functions/Mathematical.md
+++ b/docs/zh/UserGuide/Operators-Functions/Mathematical.md
@@ -69,28 +69,28 @@ It costs 0.014s
目前 IoTDB 支持下列数学函数,这些数学函数的行为与这些函数在 Java Math 标准库中对应实现的行为一致。
-| 函数名 | 输入序列类型 | 输出序列类型 | Java 标准库中的对应实现 |
-| ------- | ------------------------------ | ------------------------ | ------------------------------------------------------------ |
-| SIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sin(double) |
-| COS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#cos(double) |
-| TAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#tan(double) |
-| ASIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#asin(double) |
-| ACOS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#acos(double) |
-| ATAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#atan(double) |
-| SINH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sinh(double) |
-| COSH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#cosh(double) |
-| TANH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#tanh(double) |
-| DEGREES | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#toDegrees(double) |
-| RADIANS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#toRadians(double) |
-| ABS | INT32 / INT64 / FLOAT / DOUBLE | 与输入序列的实际类型一致 | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
-| SIGN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#signum(double) |
-| CEIL | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#ceil(double) |
-| FLOOR | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#floor(double) |
-| ROUND | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#rint(double) |
-| EXP | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#exp(double) |
-| LN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#log(double) |
-| LOG10 | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#log10(double) |
-| SQRT | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sqrt(double) |
+| 函数名 | 输入序列类型 | 输出序列类型 | 必要属性参数 | Java 标准库中的对应实现 |
+| ------- | ------------------------------ | ------------------------ |-----------| ------------------------------------------------------------ |
+| SIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sin(double) |
+| COS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#cos(double) |
+| TAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#tan(double) |
+| ASIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#asin(double) |
+| ACOS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#acos(double) |
+| ATAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#atan(double) |
+| SINH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sinh(double) |
+| COSH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#cosh(double) |
+| TANH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#tanh(double) |
+| DEGREES | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#toDegrees(double) |
+| RADIANS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#toRadians(double) |
+| ABS | INT32 / INT64 / FLOAT / DOUBLE | 与输入序列的实际类型一致 | | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
+| SIGN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#signum(double) |
+| CEIL | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#ceil(double) |
+| FLOOR | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#floor(double) |
+| ROUND | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE |`places`:四舍五入有效位数,正数为小数点后面的有效位数,负数为整数位的有效位数 | Math#rint(Math#pow(10,places))/Math#pow(10,places)|
+| EXP | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#exp(double) |
+| LN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#log(double) |
+| LOG10 | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#log10(double) |
+| SQRT | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sqrt(double) |
例如:
@@ -113,4 +113,23 @@ select s1, sin(s1), cos(s1), tan(s1) from root.sg1.d1 limit 5 offset 1000;
Total line number = 5
It costs 0.008s
```
+#### ROUND
+例如:
+```sql
+select s4,round(s4),round(s4,2),round(s4,-1) from root.sg1.d1
+```
+```sql
++-----------------------------+-------------+--------------------+----------------------+-----------------------+
+| Time|root.db.d1.s4|ROUND(root.db.d1.s4)|ROUND(root.db.d1.s4,2)|ROUND(root.db.d1.s4,-1)|
++-----------------------------+-------------+--------------------+----------------------+-----------------------+
+|1970-01-01T08:00:00.001+08:00| 101.14345| 101.0| 101.14| 100.0|
+|1970-01-01T08:00:00.002+08:00| 20.144346| 20.0| 20.14| 20.0|
+|1970-01-01T08:00:00.003+08:00| 20.614372| 21.0| 20.61| 20.0|
+|1970-01-01T08:00:00.005+08:00| 20.814346| 21.0| 20.81| 20.0|
+|1970-01-01T08:00:00.006+08:00| 60.71443| 61.0| 60.71| 60.0|
+|2023-03-13T16:16:19.764+08:00| 10.143425| 10.0| 10.14| 10.0|
++-----------------------------+-------------+--------------------+----------------------+-----------------------+
+Total line number = 6
+It costs 0.059s
+```
diff --git a/docs/zh/UserGuide/Operators-Functions/Overview.md b/docs/zh/UserGuide/Operators-Functions/Overview.md
index a57117cf2c..be0b9ff3f9 100644
--- a/docs/zh/UserGuide/Operators-Functions/Overview.md
+++ b/docs/zh/UserGuide/Operators-Functions/Overview.md
@@ -112,28 +112,28 @@ OR, |, ||
### 数学函数
-| 函数名 | 输入序列类型 | 输出序列类型 | Java 标准库中的对应实现 |
-| ------- | ------------------------------ | ------------------------ | ------------------------------------------------------------ |
-| SIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sin(double) |
-| COS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#cos(double) |
-| TAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#tan(double) |
-| ASIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#asin(double) |
-| ACOS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#acos(double) |
-| ATAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#atan(double) |
-| SINH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sinh(double) |
-| COSH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#cosh(double) |
-| TANH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#tanh(double) |
-| DEGREES | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#toDegrees(double) |
-| RADIANS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#toRadians(double) |
-| ABS | INT32 / INT64 / FLOAT / DOUBLE | 与输入序列的实际类型一致 | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
-| SIGN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#signum(double) |
-| CEIL | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#ceil(double) |
-| FLOOR | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#floor(double) |
-| ROUND | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#rint(double) |
-| EXP | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#exp(double) |
-| LN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#log(double) |
-| LOG10 | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#log10(double) |
-| SQRT | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | Math#sqrt(double) |
+| 函数名 | 输入序列类型 | 输出序列类型 | 必要属性参数 | Java 标准库中的对应实现 |
+| ------- | ------------------------------ | ------------------------ |----------------------------------------------|-------------------------------------------------------------------|
+| SIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sin(double) |
+| COS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#cos(double) |
+| TAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#tan(double) |
+| ASIN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#asin(double) |
+| ACOS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#acos(double) |
+| ATAN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#atan(double) |
+| SINH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sinh(double) |
+| COSH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#cosh(double) |
+| TANH | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#tanh(double) |
+| DEGREES | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#toDegrees(double) |
+| RADIANS | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#toRadians(double) |
+| ABS | INT32 / INT64 / FLOAT / DOUBLE | 与输入序列的实际类型一致 | | Math#abs(int) / Math#abs(long) /Math#abs(float) /Math#abs(double) |
+| SIGN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#signum(double) |
+| CEIL | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#ceil(double) |
+| FLOOR | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#floor(double) |
+| ROUND | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | `places`:四舍五入有效位数,正数为小数点后面的有效位数,负数为整数位的有效位数 | Math#rint(Math#pow(10,places))/Math#pow(10,places) |
+| EXP | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#exp(double) |
+| LN | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#log(double) |
+| LOG10 | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#log10(double) |
+| SQRT | INT32 / INT64 / FLOAT / DOUBLE | DOUBLE | | Math#sqrt(double) |
详细说明及示例见文档 [算数运算符和函数](./Mathematical.md)。
diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinScalarFunctionEnum.java b/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinScalarFunctionEnum.java
index 9518a2d546..3784af7c61 100644
--- a/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinScalarFunctionEnum.java
+++ b/integration-test/src/main/java/org/apache/iotdb/itbase/constant/BuiltinScalarFunctionEnum.java
@@ -23,6 +23,7 @@ public enum BuiltinScalarFunctionEnum {
DIFF("diff"),
CAST("cast"),
REPLACE("replace"),
+ ROUND("round");
;
private final String 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 2b98a13fd9..cf3b130a48 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
@@ -38,7 +38,6 @@ public enum BuiltinTimeSeriesGeneratingFunctionEnum {
SIGN("SIGN"),
CEIL("CEIL"),
FLOOR("FLOOR"),
- ROUND("ROUND"),
EXP("EXP"),
LN("LN"),
LOG10("LOG10"),
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/builtinfunction/scalar/IoTDBRoundFunctionIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/builtinfunction/scalar/IoTDBRoundFunctionIT.java
new file mode 100644
index 0000000000..a34e069baa
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/builtinfunction/scalar/IoTDBRoundFunctionIT.java
@@ -0,0 +1,327 @@
+/*
+ * 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.apache.iotdb.rpc.TSStatusCode;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import static org.apache.iotdb.db.it.utils.TestUtils.assertTestFail;
+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;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBRoundFunctionIT {
+ protected static final String[] SQLs =
+ new String[] {
+ "CREATE DATABASE root.db",
+ "CREATE DATABASE root.db1",
+ "CREATE TIMESERIES root.db.d1.s1 WITH DATATYPE=INT32, ENCODING=PLAIN tags(city=Beijing)",
+ "CREATE TIMESERIES root.db.d1.s2 WITH DATATYPE=INT64, ENCODING=PLAIN tags(city=Nanjing)",
+ "CREATE TIMESERIES root.db.d1.s3 WITH DATATYPE=DOUBLE, ENCODING=PLAIN tags(city=Nanjing)",
+ "CREATE TIMESERIES root.db.d1.s4 WITH DATATYPE=FLOAT, ENCODING=PLAIN tags(city=Nanjing)",
+ "CREATE TIMESERIES root.db.d1.s5 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN tags(city=Nanjing)",
+ "CREATE TIMESERIES root.db.d1.s6 WITH DATATYPE=TEXT, ENCODING=PLAIN tags(city=Nanjing)",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(1, 2, 3, 0.11234, 101.143445345,true,null)",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(2, 2, 4, 10.11234, 20.1443465345,true,'sss')",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(3, 2, 555, 120.161234, 20.61437245345,true,'sss')",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(4, 2, 12341234, 101.131234, null,true,'sss')",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(5, 2, 55678, 90.116234, 20.8143454345,true,'sss')",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(6, 2, 12355, null, 60.71443345345,true,'sss')",
+ "INSERT INTO root.db.d1(timestamp,s1,s2,s3,s4,s5,s6) values(1678695379764, 2, 12345, 120.511234, 10.143425345,null,'sss')",
+ "flush"
+ };
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ EnvFactory.getEnv().getConfig().getCommonConfig().setPartitionInterval(1000);
+ EnvFactory.getEnv().initClusterEnvironment();
+ prepareData(SQLs);
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ EnvFactory.getEnv().cleanClusterEnvironment();
+ }
+
+ @Test
+ public void testRound() {
+ String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s1)"};
+ String[] intRetArray =
+ new String[] {
+ "1,2.0,", "2,2.0,", "3,2.0,", "4,2.0,", "5,2.0,", "6,2.0,", "1678695379764,2.0,",
+ };
+ resultSetEqualTest("select round(s1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s2)"};
+ intRetArray =
+ new String[] {
+ "1,3.0,",
+ "2,4.0,",
+ "3,555.0,",
+ "4,1.2341234E7,",
+ "5,55678.0,",
+ "6,12355.0,",
+ "1678695379764,12345.0,",
+ };
+ resultSetEqualTest("select round(s2) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s3)"};
+ intRetArray =
+ new String[] {
+ "1,0.0,", "2,10.0,", "3,120.0,", "4,101.0,", "5,90.0,", "1678695379764,121.0,",
+ };
+ resultSetEqualTest("select round(s3) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s4)"};
+ intRetArray =
+ new String[] {
+ "1,101.0,", "2,20.0,", "3,21.0,", "5,21.0,", "6,61.0,", "1678695379764,10.0,",
+ };
+ resultSetEqualTest("select round(s4) from root.**", intExpectedHeader, intRetArray);
+ }
+
+ @Test
+ public void testRoundWithPlaces() {
+ String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s1,1)"};
+ String[] intRetArray =
+ new String[] {
+ "1,2.0,", "2,2.0,", "3,2.0,", "4,2.0,", "5,2.0,", "6,2.0,", "1678695379764,2.0,",
+ };
+ resultSetEqualTest("select round(s1,1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s2,1)"};
+ intRetArray =
+ new String[] {
+ "1,3.0,",
+ "2,4.0,",
+ "3,555.0,",
+ "4,1.2341234E7,",
+ "5,55678.0,",
+ "6,12355.0,",
+ "1678695379764,12345.0,",
+ };
+ resultSetEqualTest("select round(s2,1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s3,1)"};
+ intRetArray =
+ new String[] {
+ "1,0.1,", "2,10.1,", "3,120.2,", "4,101.1,", "5,90.1,", "1678695379764,120.5,",
+ };
+ resultSetEqualTest("select round(s3,1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s3,2)"};
+ intRetArray =
+ new String[] {
+ "1,0.11,", "2,10.11,", "3,120.16,", "4,101.13,", "5,90.12,", "1678695379764,120.51,",
+ };
+ resultSetEqualTest("select round(s3,2) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s3,3)"};
+ intRetArray =
+ new String[] {
+ "1,0.112,",
+ "2,10.112,",
+ "3,120.161,",
+ "4,101.131,",
+ "5,90.116,",
+ "1678695379764,120.511,",
+ };
+ resultSetEqualTest("select round(s3,3) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s3,4)"};
+ intRetArray =
+ new String[] {
+ "1,0.1123,",
+ "2,10.1123,",
+ "3,120.1612,",
+ "4,101.1312,",
+ "5,90.1162,",
+ "1678695379764,120.5112,",
+ };
+ resultSetEqualTest("select round(s3,4) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s4,5)"};
+ intRetArray =
+ new String[] {
+ "1,101.14345,",
+ "2,20.14435,",
+ "3,20.61437,",
+ "5,20.81435,",
+ "6,60.71443,",
+ "1678695379764,10.14342,",
+ };
+ resultSetEqualTest("select round(s4,5) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s4,1)"};
+ intRetArray =
+ new String[] {
+ "1,101.1,", "2,20.1,", "3,20.6,", "5,20.8,", "6,60.7,", "1678695379764,10.1,",
+ };
+ resultSetEqualTest("select round(s4,1) from root.**", intExpectedHeader, intRetArray);
+ }
+
+ @Test
+ public void testRoundWithNegativePlaces() {
+ String[] intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s1,-1)"};
+ String[] intRetArray =
+ new String[] {
+ "1,0.0,", "2,0.0,", "3,0.0,", "4,0.0,", "5,0.0,", "6,0.0,", "1678695379764,0.0,",
+ };
+ resultSetEqualTest("select round(s1,-1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s2,-1)"};
+ intRetArray =
+ new String[] {
+ "1,0.0,",
+ "2,0.0,",
+ "3,560.0,",
+ "4,1.234123E7,",
+ "5,55680.0,",
+ "6,12360.0,",
+ "1678695379764,12340.0,",
+ };
+ resultSetEqualTest("select round(s2,-1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s3,-1)"};
+ intRetArray =
+ new String[] {
+ "1,0.0,", "2,10.0,", "3,120.0,", "4,100.0,", "5,90.0,", "1678695379764,120.0,",
+ };
+ resultSetEqualTest("select round(s3,-1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {TIMESTAMP_STR, "ROUND(root.db.d1.s4,-1)"};
+ intRetArray =
+ new String[] {
+ "1,100.0,", "2,20.0,", "3,20.0,", "5,20.0,", "6,60.0,", "1678695379764,10.0,",
+ };
+ resultSetEqualTest("select round(s4,-1) from root.**", intExpectedHeader, intRetArray);
+ }
+
+ @Test
+ public void testWithUDF() {
+ String[] intExpectedHeader =
+ new String[] {"Time,change_points(root.db.d1.s2),ROUND(root.db.d1.s2,1)"};
+ String[] intRetArray =
+ new String[] {
+ "1,3,3.0,",
+ "2,4,4.0,",
+ "3,555,555.0,",
+ "4,12341234,1.2341234E7,",
+ "5,55678,55678.0,",
+ "6,12355,12355.0,",
+ "1678695379764,12345,12345.0,",
+ };
+ resultSetEqualTest(
+ "select change_points(s2),ROUND(s2,1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {"Time,change_points(root.db.d1.s2),ROUND(root.db.d1.s3,1)"};
+ intRetArray =
+ new String[] {
+ "1,3,0.1,",
+ "2,4,10.1,",
+ "3,555,120.2,",
+ "4,12341234,101.1,",
+ "5,55678,90.1,",
+ "6,12355,null,",
+ "1678695379764,12345,120.5,",
+ };
+ resultSetEqualTest(
+ "select change_points(s2),ROUND(s3,1) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {"Time,change_points(root.db.d1.s2),ROUND(root.db.d1.s3,2)"};
+ intRetArray =
+ new String[] {
+ "1,3,0.11,",
+ "2,4,10.11,",
+ "3,555,120.16,",
+ "4,12341234,101.13,",
+ "5,55678,90.12,",
+ "6,12355,null,",
+ "1678695379764,12345,120.51,",
+ };
+ resultSetEqualTest(
+ "select change_points(s2),ROUND(s3,2) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {"Time,change_points(root.db.d1.s2),ROUND(root.db.d1.s3,3)"};
+ intRetArray =
+ new String[] {
+ "1,3,0.112,",
+ "2,4,10.112,",
+ "3,555,120.161,",
+ "4,12341234,101.131,",
+ "5,55678,90.116,",
+ "6,12355,null,",
+ "1678695379764,12345,120.511,",
+ };
+ resultSetEqualTest(
+ "select change_points(s2),ROUND(s3,3) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {"Time,change_points(root.db.d1.s2),ROUND(root.db.d1.s3,4)"};
+ intRetArray =
+ new String[] {
+ "1,3,0.1123,",
+ "2,4,10.1123,",
+ "3,555,120.1612,",
+ "4,12341234,101.1312,",
+ "5,55678,90.1162,",
+ "6,12355,null,",
+ "1678695379764,12345,120.5112,",
+ };
+ resultSetEqualTest(
+ "select change_points(s2),ROUND(s3,4) from root.**", intExpectedHeader, intRetArray);
+
+ intExpectedHeader = new String[] {"Time,change_points(root.db.d1.s2),ROUND(root.db.d1.s4,5)"};
+ intRetArray =
+ new String[] {
+ "1,3,101.14345,",
+ "2,4,20.14435,",
+ "3,555,20.61437,",
+ "4,12341234,null,",
+ "5,55678,20.81435,",
+ "6,12355,60.71443,",
+ "1678695379764,12345,10.14342,",
+ };
+ resultSetEqualTest(
+ "select change_points(s2),ROUND(s4,5) from root.**", intExpectedHeader, intRetArray);
+ }
+
+ @Test
+ public void testRoundBooleanAndText() {
+ assertTestFail(
+ "select round(s5) from root.**",
+ TSStatusCode.SEMANTIC_ERROR.getStatusCode()
+ + ": Input series of Scalar function [ROUND] only supports numeric data types [INT32, INT64, FLOAT, DOUBLE]");
+
+ assertTestFail(
+ "select round(s6) from root.**",
+ TSStatusCode.SEMANTIC_ERROR.getStatusCode()
+ + ": Input series of Scalar function [ROUND] only supports numeric data types [INT32, INT64, FLOAT, DOUBLE]");
+ }
+}
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinScalarFunction.java b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinScalarFunction.java
index 691f225eb5..d42ad6e39b 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinScalarFunction.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/BuiltinScalarFunction.java
@@ -29,6 +29,7 @@ import java.util.stream.Collectors;
public enum BuiltinScalarFunction {
DIFF("diff"),
CAST("cast"),
+ ROUND("round"),
REPLACE("replace"),
;
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 c5e8c2767f..d790d9aeba 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
@@ -50,7 +50,6 @@ public enum BuiltinTimeSeriesGeneratingFunction {
SIGN("SIGN", UDTFSign.class),
CEIL("CEIL", UDTFCeil.class),
FLOOR("FLOOR", UDTFFloor.class),
- ROUND("ROUND", UDTFRound.class),
EXP("EXP", UDTFExp.class),
LN("LN", UDTFLog.class),
LOG10("LOG10", UDTFLog10.class),
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/UDTFRound.java b/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/UDTFRound.java
deleted file mode 100644
index 85adb5f437..0000000000
--- a/node-commons/src/main/java/org/apache/iotdb/commons/udf/builtin/UDTFRound.java
+++ /dev/null
@@ -1,28 +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;
-
-public class UDTFRound extends UDTFMath {
-
- @Override
- protected void setTransformer() {
- transformer = Math::rint;
- }
-}
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 020073bb12..74fbbef9ab 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
@@ -63,6 +63,8 @@ public class SqlConstant {
public static final String CAST_FUNCTION = "CAST";
public static final String CAST_TYPE = "type";
+ public static final String ROUND_FUNCTION = "ROUND";
+ public static final String ROUND_PLACES = "PLACES";
public static final String REPLACE_FUNCTION = "REPLACE";
public static final String REPLACE_FROM = "FROM";
public static final String REPLACE_TO = "TO";
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 720a17e80e..6a36dc93c9 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
@@ -263,7 +263,7 @@ public class FunctionExpression extends Expression {
}
}
if (!functionAttributes.isEmpty()) {
- // Some builtin-scalar function may have different header.
+ // Some built-in scalar functions may have different header.
if (BuiltinScalarFunction.contains(functionName)) {
BuiltInScalarFunctionHelperFactory.createHelper(functionName)
.appendFunctionAttributes(!expressions.isEmpty(), builder, functionAttributes);
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
index 7525a4f155..ee71e1874f 100644
--- 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
@@ -80,8 +80,8 @@ public interface BuiltInScalarFunctionHelper extends BuiltInFunctionHelper {
FunctionExpression expression, LayerPointReader layerPointReader);
/**
- * Some builtin-scalar function may have a different header. This method will be called by {@link
- * FunctionExpression#getExpressionStringInternal()} )}
+ * Some built-in scalar functions may have a different header. This method will be called by
+ * {@link FunctionExpression#getExpressionStringInternal()} )}
*
* @param builder String builder in FunctionExpression. Append function attributes through it.
* @param functionAttributes attributes of the function
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelperFactory.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelperFactory.java
index f7d09a81df..f47128b81e 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelperFactory.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/BuiltInScalarFunctionHelperFactory.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.db.mpp.plan.expression.multi.builtin;
import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.helper.CastFunctionHelper;
import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.helper.DiffFunctionHelper;
import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.helper.ReplaceFunctionHelper;
+import org.apache.iotdb.db.mpp.plan.expression.multi.builtin.helper.RoundFunctionHelper;
public class BuiltInScalarFunctionHelperFactory {
public static BuiltInScalarFunctionHelper createHelper(String functionName) {
@@ -33,6 +34,8 @@ public class BuiltInScalarFunctionHelperFactory {
return new CastFunctionHelper();
case "REPLACE":
return new ReplaceFunctionHelper();
+ case "ROUND":
+ return new RoundFunctionHelper();
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/RoundFunctionHelper.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/helper/RoundFunctionHelper.java
new file mode 100644
index 0000000000..d26b3decb0
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/expression/multi/builtin/helper/RoundFunctionHelper.java
@@ -0,0 +1,84 @@
+/*
+ * 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.RoundFunctionColumnTransformer;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.Transformer;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.scalar.RoundFunctionTransformer;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.read.common.type.TypeFactory;
+
+import java.util.Map;
+
+import static org.apache.iotdb.db.constant.SqlConstant.ROUND_PLACES;
+import static org.apache.iotdb.db.mpp.plan.parser.ASTVisitor.checkFunctionExpressionInputSize;
+
+public class RoundFunctionHelper 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 [ROUND] 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 RoundFunctionColumnTransformer(
+ TypeFactory.getType(this.getBuiltInScalarFunctionReturnType(expression)),
+ columnTransformer,
+ Integer.parseInt(expression.getFunctionAttributes().getOrDefault(ROUND_PLACES, "0")));
+ }
+
+ @Override
+ public Transformer getBuiltInScalarFunctionTransformer(
+ FunctionExpression expression, LayerPointReader layerPointReader) {
+ return new RoundFunctionTransformer(
+ layerPointReader,
+ this.getBuiltInScalarFunctionReturnType(expression),
+ Integer.parseInt(expression.getFunctionAttributes().getOrDefault(ROUND_PLACES, "0")));
+ }
+
+ @Override
+ public void appendFunctionAttributes(
+ boolean hasExpression, StringBuilder builder, Map<String, String> functionAttributes) {
+ builder.append(",").append(functionAttributes.get(ROUND_PLACES));
+ }
+}
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 580ed76379..c47fed94a9 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
@@ -212,6 +212,8 @@ import static org.apache.iotdb.db.constant.SqlConstant.CAST_TYPE;
import static org.apache.iotdb.db.constant.SqlConstant.REPLACE_FROM;
import static org.apache.iotdb.db.constant.SqlConstant.REPLACE_FUNCTION;
import static org.apache.iotdb.db.constant.SqlConstant.REPLACE_TO;
+import static org.apache.iotdb.db.constant.SqlConstant.ROUND_FUNCTION;
+import static org.apache.iotdb.db.constant.SqlConstant.ROUND_PLACES;
import static org.apache.iotdb.db.metadata.MetadataConstant.ALL_RESULT_NODES;
/** Parse AST to Statement. */
@@ -2366,6 +2368,8 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
return parseCastFunction(context, canUseFullPath);
} else if (context.REPLACE() != null) {
return parseReplaceFunction(context, canUseFullPath);
+ } else if (context.ROUND() != null) {
+ return parseRoundFunction(context, canUseFullPath);
}
throw new UnsupportedOperationException();
}
@@ -2387,6 +2391,16 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
return functionExpression;
}
+ private Expression parseRoundFunction(
+ IoTDBSqlParser.ScalarFunctionExpressionContext roundClause, boolean canUseFullPath) {
+ FunctionExpression functionExpression = new FunctionExpression(ROUND_FUNCTION);
+ functionExpression.addExpression(parseExpression(roundClause.input, canUseFullPath));
+ if (roundClause.places != null) {
+ functionExpression.addAttribute(ROUND_PLACES, parseConstant(roundClause.constant()));
+ }
+ return functionExpression;
+ }
+
private Expression parseFunctionExpression(
IoTDBSqlParser.ExpressionContext functionClause, boolean canUseFullPath) {
FunctionExpression functionExpression =
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/RoundFunctionColumnTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/RoundFunctionColumnTransformer.java
new file mode 100644
index 0000000000..193db12890
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/column/unary/scalar/RoundFunctionColumnTransformer.java
@@ -0,0 +1,72 @@
+/*
+ * 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.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;
+
+public class RoundFunctionColumnTransformer extends UnaryColumnTransformer {
+
+ protected int places;
+
+ public RoundFunctionColumnTransformer(
+ Type returnType, ColumnTransformer childColumnTransformer, int places) {
+ super(returnType, childColumnTransformer);
+ this.places = places;
+ }
+
+ @Override
+ protected void doTransform(Column column, ColumnBuilder columnBuilder) {
+ TypeEnum sourceType = childColumnTransformer.getType().getTypeEnum();
+ for (int i = 0, n = column.getPositionCount(); i < n; i++) {
+ if (!column.isNull(i)) {
+ switch (sourceType) {
+ case INT32:
+ columnBuilder.writeDouble(
+ Math.rint(column.getInt(i) * Math.pow(10, places)) / Math.pow(10, places));
+ break;
+ case INT64:
+ columnBuilder.writeDouble(
+ Math.rint(column.getLong(i) * Math.pow(10, places)) / Math.pow(10, places));
+ break;
+ case FLOAT:
+ columnBuilder.writeDouble(
+ Math.rint(column.getFloat(i) * Math.pow(10, places)) / Math.pow(10, places));
+ break;
+ case DOUBLE:
+ columnBuilder.writeDouble(
+ Math.rint(column.getDouble(i) * Math.pow(10, places)) / Math.pow(10, places));
+ break;
+ default:
+ throw new UnsupportedOperationException(
+ String.format(
+ "Unsupported source dataType: %s",
+ childColumnTransformer.getType().getTypeEnum()));
+ }
+ } else {
+ columnBuilder.appendNull();
+ }
+ }
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/RoundFunctionTransformer.java b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/RoundFunctionTransformer.java
new file mode 100644
index 0000000000..2dff19193e
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/transformation/dag/transformer/unary/scalar/RoundFunctionTransformer.java
@@ -0,0 +1,72 @@
+/*
+ * 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.transformation.api.LayerPointReader;
+import org.apache.iotdb.db.mpp.transformation.dag.transformer.unary.UnaryTransformer;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+import java.io.IOException;
+
+public class RoundFunctionTransformer extends UnaryTransformer {
+ private final TSDataType targetDataType;
+
+ protected int places;
+
+ public RoundFunctionTransformer(
+ LayerPointReader layerPointReader, TSDataType targetDataType, int places) {
+ super(layerPointReader);
+ this.targetDataType = targetDataType;
+ this.places = places;
+ }
+
+ @Override
+ public TSDataType getDataType() {
+ return targetDataType;
+ }
+
+ @Override
+ protected void transformAndCache() throws QueryProcessException, IOException {
+ switch (layerPointReaderDataType) {
+ case INT32:
+ cachedDouble =
+ Math.rint(layerPointReader.currentInt() * Math.pow(10, places)) / Math.pow(10, places);
+ return;
+ case INT64:
+ cachedDouble =
+ Math.rint(layerPointReader.currentLong() * Math.pow(10, places)) / Math.pow(10, places);
+ return;
+ case FLOAT:
+ cachedDouble =
+ Math.rint(layerPointReader.currentFloat() * Math.pow(10, places))
+ / Math.pow(10, places);
+ return;
+ case DOUBLE:
+ cachedDouble =
+ Math.rint(layerPointReader.currentDouble() * Math.pow(10, places))
+ / Math.pow(10, places);
+ return;
+ default:
+ throw new UnsupportedOperationException(
+ String.format("Unsupported source dataType: %s", layerPointReaderDataType));
+ }
+ }
+}