You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ro...@apache.org on 2021/12/13 04:46:57 UTC

[iotdb] branch master updated: [IOTDB-1973] Supports aggregate queries, constants, and arithmetic nested expressions in SELECT clauses (#4453)

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

rong 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 9d2df64  [IOTDB-1973] Supports aggregate queries, constants, and arithmetic nested expressions in SELECT clauses (#4453)
9d2df64 is described below

commit 9d2df64422238222ac7b65ab1040894d910148ce
Author: LLY <48...@users.noreply.github.com>
AuthorDate: Mon Dec 13 12:46:04 2021 +0800

    [IOTDB-1973] Supports aggregate queries, constants, and arithmetic nested expressions in SELECT clauses (#4453)
    
    Co-authored-by: Steve Yurong Su <ro...@apache.org>
---
 .../DML-Data-Manipulation-Language.md              |  27 +-
 .../DML-Data-Manipulation-Language.md              |  29 +-
 .../IoTDBUserDefinedAggregationFunctionIT.java     | 725 +++++++++++++++++++++
 .../iotdb/db/qp/logical/crud/QueryOperator.java    |   2 +-
 .../iotdb/db/qp/logical/crud/SelectComponent.java  |  21 +-
 .../db/qp/logical/crud/UDAFQueryOperator.java      |  45 +-
 ...DFQueryOperator.java => UDTFQueryOperator.java} |   6 +-
 .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java    |  11 +-
 .../iotdb/db/qp/utils/GroupByLevelController.java  |   4 +-
 .../iotdb/db/query/expression/Expression.java      |   4 +-
 .../query/expression/binary/BinaryExpression.java  |  12 +-
 .../query/expression/unary/FunctionExpression.java |  38 +-
 .../query/expression/unary/NegationExpression.java |   7 +-
 13 files changed, 858 insertions(+), 73 deletions(-)

diff --git a/docs/UserGuide/IoTDB-SQL-Language/DML-Data-Manipulation-Language.md b/docs/UserGuide/IoTDB-SQL-Language/DML-Data-Manipulation-Language.md
index 062e4cd..8597e7e 100644
--- a/docs/UserGuide/IoTDB-SQL-Language/DML-Data-Manipulation-Language.md
+++ b/docs/UserGuide/IoTDB-SQL-Language/DML-Data-Manipulation-Language.md
@@ -1115,6 +1115,28 @@ Total line number = 1
 It costs 0.009s
 ```
 
+Input:
+
+```sql
+select count(a),
+       count(b),
+       ((count(a) + 1) * 2 - 1) % 2 + 1.5,
+       -(count(a) + count(b)) * (count(a) * count(b)) + count(a) / count(b)
+from root.sg;
+```
+
+Result:
+
+```
++----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+
+|count(root.sg.a)|count(root.sg.b)|((((count(root.sg.a) + 1) * 2) - 1) % 2) + 1.5|(-count(root.sg.a) + count(root.sg.b) * (count(root.sg.a) * count(root.sg.b))) + (count(root.sg.a) / count(root.sg.b))|
++----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+
+|               4|               3|                                           2.5|                                                                                                    -82.66666666666667|
++----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+
+Total line number = 1
+It costs 0.013s
+```
+
 2. Aggregation with `GROUP BY`.
 
 Input:
@@ -1158,8 +1180,8 @@ It costs 0.012s
 > ```sql
 > SELECT avg(s1+1) FROM root.sg.d1; -- The aggregation function has expression parameters.
 > SELECT avg(s1) + avg(s2) FROM root.sg.* GROUP BY LEVEL=1; -- Grouped by level
-> SELECT avg(s1) + avg(s2) FROM root.sg.d1 GROUP BY([0, 10000), 1s) FILL(double [previous]); -- Automated fill 
-> ``` 
+> SELECT avg(s1) + avg(s2) FROM root.sg.d1 GROUP BY([0, 10000), 1s) FILL(double [previous]); -- Automated fill
+> ```
 
 ### Automated Fill
 
@@ -1183,6 +1205,7 @@ Detailed descriptions of all parameters are given in Table 3-4.
 
 **Table 3-4 Previous fill paramter list**
 
+
 |Parameter name (case insensitive)|Interpretation|
 |:---|:---|
 |path, prefixPath|query path; mandatory field|
diff --git a/docs/zh/UserGuide/IoTDB-SQL-Language/DML-Data-Manipulation-Language.md b/docs/zh/UserGuide/IoTDB-SQL-Language/DML-Data-Manipulation-Language.md
index 79bb8c7..db90614 100644
--- a/docs/zh/UserGuide/IoTDB-SQL-Language/DML-Data-Manipulation-Language.md
+++ b/docs/zh/UserGuide/IoTDB-SQL-Language/DML-Data-Manipulation-Language.md
@@ -1089,14 +1089,13 @@ select count(status) from root.ln.wf01.wt01 group by ([0,20),2ms,3ms), level=1;
 Total line number = 7
 It costs 0.004s
 ```
-
 #### 聚合查询嵌套表达式
 
 IoTDB 支持在 `SELECT` 字句中执行由聚合查询和其他运算组成的任意嵌套表达式。
 
 ##### 示例
 
-不指定 `GROUP BY` 的聚合查询。
+1. 不指定 `GROUP BY` 的聚合查询。
 
 输入:
 
@@ -1121,7 +1120,29 @@ Total line number = 1
 It costs 0.009s
 ```
 
-指定 `GROUP BY` 的聚合查询。
+输入:
+
+```sql
+select count(a),
+       count(b),
+       ((count(a) + 1) * 2 - 1) % 2 + 1.5,
+       -(count(a) + count(b)) * (count(a) * count(b)) + count(a) / count(b)
+from root.sg;
+```
+
+结果:
+
+```
++----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+
+|count(root.sg.a)|count(root.sg.b)|((((count(root.sg.a) + 1) * 2) - 1) % 2) + 1.5|(-count(root.sg.a) + count(root.sg.b) * (count(root.sg.a) * count(root.sg.b))) + (count(root.sg.a) / count(root.sg.b))|
++----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+
+|               4|               3|                                           2.5|                                                                                                    -82.66666666666667|
++----------------+----------------+----------------------------------------------+----------------------------------------------------------------------------------------------------------------------+
+Total line number = 1
+It costs 0.013s
+```
+
+2. 指定 `GROUP BY` 的聚合查询。
 
 输入:
 
@@ -1165,7 +1186,7 @@ It costs 0.012s
 > SELECT avg(s1+1) FROM root.sg.d1; -- 聚合函数内部有表达式
 > SELECT avg(s1) + avg(s2) FROM root.sg.* GROUP BY LEVEL=1; -- 按层级聚合
 > SELECT avg(s1) + avg(s2) FROM root.sg.d1 GROUP BY([0, 10000), 1s) FILL(double [previous]); -- 空值填充 
-> ```  
+> ```
 
 ### 空值填充
 
diff --git a/integration/src/test/java/org/apache/iotdb/db/integration/aggregation/IoTDBUserDefinedAggregationFunctionIT.java b/integration/src/test/java/org/apache/iotdb/db/integration/aggregation/IoTDBUserDefinedAggregationFunctionIT.java
new file mode 100644
index 0000000..3e2fecc
--- /dev/null
+++ b/integration/src/test/java/org/apache/iotdb/db/integration/aggregation/IoTDBUserDefinedAggregationFunctionIT.java
@@ -0,0 +1,725 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.integration.aggregation;
+
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.jdbc.Config;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.Locale;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
+
+public class IoTDBUserDefinedAggregationFunctionIT {
+
+  private static final double DETLA = 1e-6;
+  private static final String TIMESTAMP_STR = "Time";
+  private static final String TEMPERATURE_STR = "root.ln.wf01.wt01.temperature";
+
+  private static String[] creationSqls =
+      new String[] {
+        "SET STORAGE GROUP TO root.vehicle.d0",
+        "SET STORAGE GROUP TO root.vehicle.d1",
+        "CREATE TIMESERIES root.vehicle.d0.s0 WITH DATATYPE=INT32, ENCODING=RLE",
+        "CREATE TIMESERIES root.vehicle.d0.s1 WITH DATATYPE=INT64, ENCODING=RLE",
+        "CREATE TIMESERIES root.vehicle.d0.s2 WITH DATATYPE=FLOAT, ENCODING=RLE",
+        "CREATE TIMESERIES root.vehicle.d0.s3 WITH DATATYPE=TEXT, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.vehicle.d0.s4 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN"
+      };
+  private static String[] dataSet2 =
+      new String[] {
+        "SET STORAGE GROUP TO root.ln.wf01.wt01",
+        "CREATE TIMESERIES root.ln.wf01.wt01.status WITH DATATYPE=BOOLEAN, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.ln.wf01.wt01.temperature WITH DATATYPE=FLOAT, ENCODING=PLAIN",
+        "CREATE TIMESERIES root.ln.wf01.wt01.hardware WITH DATATYPE=INT32, ENCODING=PLAIN",
+        "INSERT INTO root.ln.wf01.wt01(timestamp,temperature,status, hardware) "
+            + "values(1, 1.1, false, 11)",
+        "INSERT INTO root.ln.wf01.wt01(timestamp,temperature,status, hardware) "
+            + "values(2, 2.2, true, 22)",
+        "INSERT INTO root.ln.wf01.wt01(timestamp,temperature,status, hardware) "
+            + "values(3, 3.3, false, 33 )",
+        "INSERT INTO root.ln.wf01.wt01(timestamp,temperature,status, hardware) "
+            + "values(4, 4.4, false, 44)",
+        "INSERT INTO root.ln.wf01.wt01(timestamp,temperature,status, hardware) "
+            + "values(5, 5.5, false, 55)"
+      };
+  private static String[] dataSet3 =
+      new String[] {
+        "SET STORAGE GROUP TO root.sg",
+        "CREATE TIMESERIES root.sg.d1.s1 WITH DATATYPE=INT32, ENCODING=RLE",
+        "insert into root.sg.d1(timestamp,s1) values(5,5)",
+        "insert into root.sg.d1(timestamp,s1) values(12,12)",
+        "flush",
+        "insert into root.sg.d1(timestamp,s1) values(15,15)",
+        "insert into root.sg.d1(timestamp,s1) values(25,25)",
+        "flush",
+        "insert into root.sg.d1(timestamp,s1) values(1,111)",
+        "insert into root.sg.d1(timestamp,s1) values(20,200)",
+        "flush"
+      };
+  private final String d0s0 = "root.vehicle.d0.s0";
+  private final String d0s1 = "root.vehicle.d0.s1";
+  private final String d0s2 = "root.vehicle.d0.s2";
+  private final String d0s3 = "root.vehicle.d0.s3";
+  private static final String insertTemplate =
+      "INSERT INTO root.vehicle.d0(timestamp,s0,s1,s2,s3,s4)" + " VALUES(%d,%d,%d,%f,%s,%s)";
+  private static long prevPartitionInterval =
+      IoTDBDescriptor.getInstance().getConfig().getPartitionInterval();
+
+  @BeforeClass
+  public static void setUp() throws Exception {
+    EnvironmentUtils.closeStatMonitor();
+    IoTDBDescriptor.getInstance().getConfig().setPartitionInterval(1000);
+    EnvironmentUtils.envSetUp();
+    Class.forName(Config.JDBC_DRIVER_NAME);
+    prepareData();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    EnvironmentUtils.cleanEnv();
+    IoTDBDescriptor.getInstance().getConfig().setPartitionInterval(prevPartitionInterval);
+  }
+
+  // add test for part of points in page don't satisfy filter
+  // details in: https://issues.apache.org/jira/projects/IOTDB/issues/IOTDB-54
+  @Test
+  public void additionTest1() {
+    String[] retArray = new String[] {"0,3.0", "0,6.0,7.0", "0,4.0,6.0"};
+    try (Connection connection =
+            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+
+      boolean hasResultSet =
+          statement.execute(
+              "SELECT count(temperature) + 1 FROM root.ln.wf01.wt01 WHERE hardware > 35");
+
+      Assert.assertTrue(hasResultSet);
+      int cnt;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          String ans = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(1);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT count(temperature) + 1 FROM root.ln.wf01.wt01 WHERE hardware > 35 order by time desc");
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          String ans = resultSet.getString(TIMESTAMP_STR) + "," + resultSet.getString(1);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT count(temperature) + min_time(temperature), count(temperature) + max_time(temperature) FROM root.ln.wf01.wt01 WHERE time > 3");
+
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + Double.valueOf(resultSet.getString(2)).toString();
+          Assert.assertEquals(retArray[cnt], ans);
+        }
+        Assert.assertEquals(1, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT count(temperature) + min_time(temperature), count(temperature) + max_time(temperature) FROM root.ln.wf01.wt01 WHERE time > 3 order by time desc ");
+
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(2, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT min_time(temperature), count(temperature) + min_time(temperature) FROM root.ln.wf01.wt01 WHERE time > 3");
+
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          cnt++;
+        }
+        Assert.assertEquals(3, cnt);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void addtionTest2() {
+    String[] retArray =
+        new String[] {
+          "0,2002.0,2003.0,2004.0,2005.0", "0,15000.0,7500,7500", "0,7500,15000.0,7500"
+        };
+    try (Connection connection =
+            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+      boolean hasResultSet =
+          statement.execute(
+              "SELECT count(s0)+1,count(s1)+2,count(s2)+3,count(s3)+4 "
+                  + "FROM root.vehicle.d0 WHERE time >= 6000 AND time <= 9000");
+
+      Assert.assertTrue(hasResultSet);
+      int cnt;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2)
+                  + ","
+                  + resultSet.getString(3)
+                  + ","
+                  + resultSet.getString(4);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+      // keep the correctness of `order by time desc`
+      hasResultSet =
+          statement.execute(
+              "SELECT count(s0)+1,count(s1)+2,count(s2)+3,count(s3)+4 "
+                  + "FROM root.vehicle.d0 WHERE time >= 6000 AND time <= 9000 order by time desc");
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2)
+                  + ","
+                  + resultSet.getString(3)
+                  + ","
+                  + resultSet.getString(4);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT count(s0)+count(s1),count(s2),count(s3) " + "FROM root.vehicle.d0");
+
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 1;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2)
+                  + ","
+                  + resultSet.getString(3);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(2, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT count(s0)+count(s1),count(s2),count(s3) "
+                  + "FROM root.vehicle.d0 order by time desc");
+
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 1;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2)
+                  + ","
+                  + resultSet.getString(3);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(2, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT count(s0),count(s0)+count(s1),count(s2) " + "FROM root.vehicle.d0");
+
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 2;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2)
+                  + ","
+                  + resultSet.getString(3);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(3, cnt);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void polyNominalWithFirstAndLastValueTest() {
+    String[] retArray = new String[] {"0,10001.0,2000"};
+    try (Connection connection =
+            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+
+      boolean hasResultSet =
+          statement.execute(
+              "SELECT ((first_value(s0)+ last_value(s1))*2-first_value(s2)+2)/2, first_value(s1) "
+                  + "FROM root.vehicle.d0 WHERE time >= 1500 AND time <= 9000");
+      Assert.assertTrue(hasResultSet);
+      int cnt;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT ((first_value(s0)+ last_value(s1))*2-first_value(s2)+2)/2, first_value(s1) "
+                  + "FROM root.vehicle.d0 WHERE time >= 1500 AND time <= 9000 order by time desc");
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void polyNominalWithMaxMinTimeTest() {
+    String[] retArray = new String[] {"0,500,0.0", "0,100.0,2499", "0,-100.0,-2499"};
+    try (Connection connection =
+            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+
+      boolean hasResultSet =
+          statement.execute(
+              "SELECT min_time(s2),((max_time(s0)+min_time(s2))*2+2)%10 "
+                  + "FROM root.vehicle.d0 WHERE time >= 100 AND time < 9000");
+      Assert.assertTrue(hasResultSet);
+      int cnt;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT min_time(s2),((max_time(s0)+min_time(s2))*2+2)%10 "
+                  + "FROM root.vehicle.d0 WHERE time >= 100 AND time < 9000 order by time desc");
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 0;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT ((max_time(s0)-min_time(s2))+1)/5,max_time(s0) "
+                  + "FROM root.vehicle.d0 WHERE time <= 2500 AND time > 1800");
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 1;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(2, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT ((max_time(s0)-min_time(s2))+1)/5,max_time(s0) "
+                  + "FROM root.vehicle.d0 WHERE time <= 2500 AND time > 1800 order by time desc");
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 1;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(2, cnt);
+      }
+      hasResultSet =
+          statement.execute(
+              "SELECT -((max_time(s0)-min_time(s2))+1)/5,-max_time(s0) "
+                  + "FROM root.vehicle.d0 WHERE time <= 2500 AND time > 1800");
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 2;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(3, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT -((max_time(s0)-min_time(s2))+1)/5,-max_time(s0) "
+                  + "FROM root.vehicle.d0 WHERE time <= 2500 AND time > 1800 order by time desc");
+      Assert.assertTrue(hasResultSet);
+      try (ResultSet resultSet = statement.getResultSet()) {
+        cnt = 2;
+        while (resultSet.next()) {
+          String ans =
+              resultSet.getString(TIMESTAMP_STR)
+                  + ","
+                  + resultSet.getString(1)
+                  + ","
+                  + resultSet.getString(2);
+          Assert.assertEquals(retArray[cnt], ans);
+          cnt++;
+        }
+        Assert.assertEquals(3, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void polynominalWithAvgAndSumTest() {
+    double[][] retArray = {
+      {0.0, 2.4508E7, 6250.374812593702},
+      {0.0, 626750.0, 1250.9980039920158}
+    };
+
+    try (Connection connection =
+            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+
+      boolean hasResultSet =
+          statement.execute(
+              "SELECT sum(s0)+10000000,avg(s2)-1000"
+                  + "FROM root.vehicle.d0 WHERE time >= 6000 AND time <= 9000");
+
+      Assert.assertTrue(hasResultSet);
+      int cnt = 0;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        while (resultSet.next()) {
+          double[] ans = new double[3];
+          ans[0] = Double.valueOf(resultSet.getString(TIMESTAMP_STR));
+          ans[1] = Double.valueOf(resultSet.getString(1));
+          ans[2] = Double.valueOf(resultSet.getString(2));
+          assertArrayEquals(retArray[cnt], ans, DETLA);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+      // keep the correctness of `order by time desc`
+      hasResultSet =
+          statement.execute(
+              "SELECT sum(s0)+10000000,avg(s2)-1000"
+                  + "FROM root.vehicle.d0 WHERE time >= 6000 AND time <= 9000 order by time desc");
+
+      Assert.assertTrue(hasResultSet);
+      cnt = 0;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        while (resultSet.next()) {
+          double[] ans = new double[3];
+          ans[0] = Double.valueOf(resultSet.getString(TIMESTAMP_STR));
+          ans[1] = Double.valueOf(resultSet.getString(1));
+          ans[2] = Double.valueOf(resultSet.getString(2));
+          assertArrayEquals(retArray[cnt], ans, DETLA);
+          cnt++;
+        }
+        Assert.assertEquals(1, cnt);
+      }
+
+      hasResultSet =
+          statement.execute(
+              "SELECT (sum(s0)+15)-3*5,avg(s2)"
+                  + "FROM root.vehicle.d0 WHERE time >= 1000 AND time <= 2000");
+      Assert.assertTrue(hasResultSet);
+      cnt = 1;
+      try (ResultSet resultSet = statement.getResultSet()) {
+        while (resultSet.next()) {
+          double[] ans = new double[3];
+          ans[0] = Double.valueOf(resultSet.getString(TIMESTAMP_STR));
+          ans[1] = Double.valueOf(resultSet.getString(1));
+          ans[2] = Double.valueOf(resultSet.getString(2));
+          assertArrayEquals(retArray[cnt], ans, DETLA);
+          cnt++;
+        }
+        Assert.assertEquals(2, cnt);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void avgSumErrorTest() {
+    try (Connection connection =
+            DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+      try {
+        statement.execute(
+            "SELECT avg(s3)+1" + "FROM root.vehicle.d0 WHERE time >= 6000 AND time <= 9000");
+        try (ResultSet resultSet = statement.getResultSet()) {
+          resultSet.next();
+          fail();
+        }
+      } catch (Exception e) {
+        Assert.assertTrue(
+            e.getMessage().contains("Unsupported data type in aggregation AVG : TEXT"));
+      }
+      try {
+        statement.execute(
+            "SELECT sum(s3)+1" + "FROM root.vehicle.d0 WHERE time >= 6000 AND time <= 9000");
+        try (ResultSet resultSet = statement.getResultSet()) {
+          resultSet.next();
+          fail();
+        }
+      } catch (Exception e) {
+        Assert.assertTrue(
+            e.getMessage().contains("Unsupported data type in aggregation SUM : TEXT"));
+      }
+      try {
+        statement.execute(
+            "SELECT avg(s4)+1" + "FROM root.vehicle.d0 WHERE time >= 6000 AND time <= 9000");
+        try (ResultSet resultSet = statement.getResultSet()) {
+          resultSet.next();
+          fail();
+        }
+      } catch (Exception e) {
+        Assert.assertTrue(
+            e.getMessage().contains("Unsupported data type in aggregation AVG : BOOLEAN"));
+      }
+      try {
+        statement.execute(
+            "SELECT sum(s4)+1" + "FROM root.vehicle.d0 WHERE time >= 6000 AND time <= 9000");
+        try (ResultSet resultSet = statement.getResultSet()) {
+          resultSet.next();
+          fail();
+        }
+      } catch (Exception e) {
+        Assert.assertTrue(
+            e.getMessage().contains("Unsupported data type in aggregation SUM : BOOLEAN"));
+      }
+      try {
+        statement.execute("SELECT avg(status)+2 FROM root.ln.wf01.wt01");
+        try (ResultSet resultSet = statement.getResultSet()) {
+          resultSet.next();
+          fail();
+        }
+      } catch (Exception e) {
+        Assert.assertTrue(e.getMessage().contains("Boolean statistics does not support: avg"));
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  private static void prepareData() {
+    try (Connection connection =
+            DriverManager.getConnection(
+                Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root");
+        Statement statement = connection.createStatement()) {
+
+      for (String sql : creationSqls) {
+        statement.execute(sql);
+      }
+
+      // prepare BufferWrite file
+      for (int i = 5000; i < 7000; i++) {
+        statement.execute(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      statement.execute("FLUSH");
+      for (int i = 7500; i < 8500; i++) {
+        statement.execute(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+      statement.execute("FLUSH");
+      // prepare Unseq-File
+      for (int i = 500; i < 1500; i++) {
+        statement.execute(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      statement.execute("FLUSH");
+      for (int i = 3000; i < 6500; i++) {
+        statement.execute(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+      statement.execute("merge");
+
+      // prepare BufferWrite cache
+      for (int i = 9000; i < 10000; i++) {
+        statement.execute(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "true"));
+      }
+      // prepare Overflow cache
+      for (int i = 2000; i < 2500; i++) {
+        statement.execute(
+            String.format(
+                Locale.ENGLISH, insertTemplate, i, i, i, (double) i, "'" + i + "'", "false"));
+      }
+
+      for (String sql : dataSet3) {
+        statement.execute(sql);
+      }
+
+      for (String sql : dataSet2) {
+        statement.execute(sql);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
index 0082c20..134d57d 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java
@@ -133,7 +133,7 @@ public class QueryOperator extends Operator {
   }
 
   public boolean hasAggregationFunction() {
-    return selectComponent.hasAggregationFunction();
+    return selectComponent.hasPlainAggregationFunction();
   }
 
   public boolean hasTimeSeriesGeneratingFunction() {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
index aed3727..f06d661 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
@@ -34,7 +34,7 @@ public final class SelectComponent {
 
   private final ZoneId zoneId;
 
-  private boolean hasAggregationFunction = false;
+  private boolean hasPlainAggregationFunction = false;
   private boolean hasTimeSeriesGeneratingFunction = false;
   private boolean hasUserDefinedAggregationFunction = false;
 
@@ -50,7 +50,7 @@ public final class SelectComponent {
 
   public SelectComponent(SelectComponent selectComponent) {
     zoneId = selectComponent.zoneId;
-    hasAggregationFunction = selectComponent.hasAggregationFunction;
+    hasPlainAggregationFunction = selectComponent.hasPlainAggregationFunction;
     hasTimeSeriesGeneratingFunction = selectComponent.hasTimeSeriesGeneratingFunction;
     resultColumns.addAll(selectComponent.resultColumns);
   }
@@ -59,8 +59,12 @@ public final class SelectComponent {
     return zoneId;
   }
 
-  public boolean hasAggregationFunction() {
-    return hasAggregationFunction;
+  public void setHasPlainAggregationFunction(boolean hasPlainAggregationFunction) {
+    this.hasPlainAggregationFunction = hasPlainAggregationFunction;
+  }
+
+  public boolean hasPlainAggregationFunction() {
+    return hasPlainAggregationFunction;
   }
 
   public boolean hasTimeSeriesGeneratingFunction() {
@@ -73,12 +77,11 @@ public final class SelectComponent {
 
   public void addResultColumn(ResultColumn resultColumn) {
     resultColumns.add(resultColumn);
-    if (resultColumn.getExpression().isUDAFExpression()) {
+    if (resultColumn.getExpression().isUserDefinedAggregationFunctionExpression()) {
       hasUserDefinedAggregationFunction = true;
     }
-
-    if (resultColumn.getExpression().isAggregationFunctionExpression()) {
-      hasAggregationFunction = true;
+    if (resultColumn.getExpression().isPlainAggregationFunctionExpression()) {
+      hasPlainAggregationFunction = true;
     }
     if (resultColumn.getExpression().isTimeSeriesGeneratingFunctionExpression()) {
       hasTimeSeriesGeneratingFunction = true;
@@ -104,7 +107,7 @@ public final class SelectComponent {
         if (expression instanceof TimeSeriesOperand) {
           pathsCache.add(((TimeSeriesOperand) expression).getPath());
         } else if (expression instanceof FunctionExpression
-            && expression.isAggregationFunctionExpression()) {
+            && expression.isPlainAggregationFunctionExpression()) {
           pathsCache.add(
               ((TimeSeriesOperand) ((FunctionExpression) expression).getExpressions().get(0))
                   .getPath());
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDAFQueryOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDAFQueryOperator.java
index d6a14bd..5f61fdb 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDAFQueryOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDAFQueryOperator.java
@@ -32,23 +32,24 @@ import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 /**
  * For a UDAFPlan, we construct an inner AggregationPlan for it. Example: select
  * count(a)/count(b),count(a)+sum(b) from root.sg To init inner AggregationPlan, we will convert it
- * to statement: select count(a),count(b),count(a),sum(b) from root.sg. innerResultColumnsCache will
- * be [count(a),count(b),sum(b)].
+ * to statement: select count(a),count(b),count(a),sum(b) from root.sg innerResultColumnsCache will
+ * be [count(a),count(b),sum(b)]
  */
 public class UDAFQueryOperator extends QueryOperator {
 
-  private ArrayList<ResultColumn> innerResultColumnsCache;
+  private List<ResultColumn> innerResultColumnsCache;
 
-  private AggregationQueryOperator aggrOp;
+  private AggregationQueryOperator innerAggregationQueryOperator;
 
   public UDAFQueryOperator(AggregationQueryOperator queryOperator) {
     super(queryOperator);
-    this.aggrOp = queryOperator;
+    this.innerAggregationQueryOperator = queryOperator;
   }
 
   @Override
@@ -63,7 +64,7 @@ public class UDAFQueryOperator extends QueryOperator {
       throw new LogicalOperatorException(
           "UDF nesting aggregations in GROUP BY query does not support grouping by level now.");
     }
-    if (aggrOp instanceof GroupByFillQueryOperator) {
+    if (innerAggregationQueryOperator instanceof GroupByFillQueryOperator) {
       throw new LogicalOperatorException(
           "UDF nesting aggregations in GROUP BY query does not support FILL now.");
     }
@@ -77,7 +78,7 @@ public class UDAFQueryOperator extends QueryOperator {
     }
   }
 
-  public ArrayList<ResultColumn> getInnerResultColumnsCache() {
+  public List<ResultColumn> getInnerResultColumnsCache() {
     if (innerResultColumnsCache == null) {
       innerResultColumnsCache = new ArrayList<>();
       for (ResultColumn resultColumn : selectComponent.getResultColumns()) {
@@ -91,7 +92,7 @@ public class UDAFQueryOperator extends QueryOperator {
   private void addInnerResultColumn(Expression expression) {
     for (Iterator<Expression> it = expression.iterator(); it.hasNext(); ) {
       Expression currentExp = it.next();
-      if (currentExp.isAggregationFunctionExpression()) {
+      if (currentExp.isPlainAggregationFunctionExpression()) {
         innerResultColumnsCache.add(new ResultColumn(currentExp));
       }
     }
@@ -100,16 +101,7 @@ public class UDAFQueryOperator extends QueryOperator {
   @Override
   public PhysicalPlan generatePhysicalPlan(PhysicalGenerator generator)
       throws QueryProcessException {
-    SelectComponent copiedSelectComponent = new SelectComponent(getSelectComponent());
-    copiedSelectComponent.setResultColumns(getInnerResultColumnsCache());
-    aggrOp.setSelectComponent(copiedSelectComponent);
-    aggrOp.setFromComponent(getFromComponent());
-    aggrOp.setWhereComponent(getWhereComponent());
-    aggrOp.setSpecialClauseComponent(getSpecialClauseComponent());
-    aggrOp.setProps(getProps());
-    aggrOp.setIndexType(getIndexType());
-    aggrOp.setEnableTracing(isEnableTracing());
-    AggregationPlan innerAggregationPlan = (AggregationPlan) aggrOp.generatePhysicalPlan(generator);
+    AggregationPlan innerAggregationPlan = initInnerAggregationPlan(generator);
     PhysicalPlan physicalPlan;
     if (!isAlignByDevice()) {
       physicalPlan =
@@ -151,12 +143,27 @@ public class UDAFQueryOperator extends QueryOperator {
     return physicalPlan;
   }
 
+  private AggregationPlan initInnerAggregationPlan(PhysicalGenerator generator)
+      throws QueryProcessException {
+    SelectComponent copiedSelectComponent = new SelectComponent(getSelectComponent());
+    copiedSelectComponent.setHasPlainAggregationFunction(true);
+    copiedSelectComponent.setResultColumns(getInnerResultColumnsCache());
+    innerAggregationQueryOperator.setSelectComponent(copiedSelectComponent);
+    innerAggregationQueryOperator.setFromComponent(getFromComponent());
+    innerAggregationQueryOperator.setWhereComponent(getWhereComponent());
+    innerAggregationQueryOperator.setSpecialClauseComponent(getSpecialClauseComponent());
+    innerAggregationQueryOperator.setProps(getProps());
+    innerAggregationQueryOperator.setIndexType(getIndexType());
+    innerAggregationQueryOperator.setEnableTracing(isEnableTracing());
+    return (AggregationPlan) innerAggregationQueryOperator.generatePhysicalPlan(generator);
+  }
+
   private void checkEachExpression(Expression expression) throws LogicalOperatorException {
     if (expression instanceof TimeSeriesOperand) {
       throw new LogicalOperatorException(AggregationQueryOperator.ERROR_MESSAGE1);
     }
     // Currently, the aggregation function expression can only contain a timeseries operand.
-    if (expression.isAggregationFunctionExpression()) {
+    if (expression.isPlainAggregationFunctionExpression()) {
       if (expression.getExpressions().size() == 1
           && expression.getExpressions().get(0) instanceof TimeSeriesOperand) {
         return;
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDFQueryOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDTFQueryOperator.java
similarity index 91%
rename from server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDFQueryOperator.java
rename to server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDTFQueryOperator.java
index 4b6fdfe..df0c131 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDFQueryOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/UDTFQueryOperator.java
@@ -24,13 +24,13 @@ import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.qp.physical.crud.UDTFPlan;
 import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
 
-public class UDFQueryOperator extends QueryOperator {
+public class UDTFQueryOperator extends QueryOperator {
 
-  public UDFQueryOperator() {
+  public UDTFQueryOperator() {
     super();
   }
 
-  public UDFQueryOperator(QueryOperator queryOperator) {
+  public UDTFQueryOperator(QueryOperator queryOperator) {
     super(queryOperator);
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
index 2f891d3..c5de0d0 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
@@ -50,7 +50,7 @@ import org.apache.iotdb.db.qp.logical.crud.SelectComponent;
 import org.apache.iotdb.db.qp.logical.crud.SelectIntoOperator;
 import org.apache.iotdb.db.qp.logical.crud.SpecialClauseComponent;
 import org.apache.iotdb.db.qp.logical.crud.UDAFQueryOperator;
-import org.apache.iotdb.db.qp.logical.crud.UDFQueryOperator;
+import org.apache.iotdb.db.qp.logical.crud.UDTFQueryOperator;
 import org.apache.iotdb.db.qp.logical.crud.WhereComponent;
 import org.apache.iotdb.db.qp.logical.sys.ActivateTemplateOperator;
 import org.apache.iotdb.db.qp.logical.sys.AlterTimeSeriesOperator;
@@ -2531,14 +2531,14 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
     for (IoTDBSqlParser.ResultColumnContext resultColumnContext : ctx.resultColumn()) {
       selectComponent.addResultColumn(parseResultColumn(resultColumnContext));
     }
-
+    // judge query type
     if (!hasDecidedQueryType()) {
       if (selectComponent.hasUserDefinedAggregationFunction()) {
         queryOp = new UDAFQueryOperator(new AggregationQueryOperator(queryOp));
-      } else if (selectComponent.hasAggregationFunction()) {
+      } else if (selectComponent.hasPlainAggregationFunction()) {
         queryOp = new AggregationQueryOperator(queryOp);
       } else if (selectComponent.hasTimeSeriesGeneratingFunction()) {
-        queryOp = new UDFQueryOperator(queryOp);
+        queryOp = new UDTFQueryOperator(queryOp);
       }
     } else if (selectComponent.hasUserDefinedAggregationFunction()) {
       queryOp = new UDAFQueryOperator((AggregationQueryOperator) (queryOp));
@@ -2717,7 +2717,8 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
         || queryOp instanceof FillQueryOperator
         || queryOp instanceof LastQueryOperator
         || queryOp instanceof AggregationQueryOperator
-        || queryOp instanceof UDFQueryOperator;
+        || queryOp instanceof UDTFQueryOperator
+        || queryOp instanceof UDAFQueryOperator;
   }
 
   private String parseStringWithQuotes(String src) {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/utils/GroupByLevelController.java b/server/src/main/java/org/apache/iotdb/db/qp/utils/GroupByLevelController.java
index 48556cd..8c09b2b 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/utils/GroupByLevelController.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/utils/GroupByLevelController.java
@@ -76,7 +76,7 @@ public class GroupByLevelController {
     for (Iterator<Expression> it = rawColumn.getExpression().iterator(); it.hasNext(); ) {
       Expression expression = it.next();
       if (expression instanceof FunctionExpression
-          && expression.isAggregationFunctionExpression()
+          && expression.isPlainAggregationFunctionExpression()
           && ((FunctionExpression) expression).isCountStar()) {
         countWildcardIterIndices.add(idx);
       }
@@ -93,7 +93,7 @@ public class GroupByLevelController {
       for (Iterator<Expression> it = rootExpression.iterator(); it.hasNext(); ) {
         Expression expression = it.next();
         if (expression instanceof FunctionExpression
-            && expression.isAggregationFunctionExpression()) {
+            && expression.isPlainAggregationFunctionExpression()) {
           hasAggregation = true;
           List<PartialPath> paths = ((FunctionExpression) expression).getPaths();
           String functionName = ((FunctionExpression) expression).getFunctionName();
diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java b/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java
index 0bf537d..92bd9bc 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java
@@ -46,11 +46,11 @@ public abstract class Expression {
   private String expressionStringCache;
   protected Boolean isConstantOperandCache = null;
 
-  public boolean isAggregationFunctionExpression() {
+  public boolean isPlainAggregationFunctionExpression() {
     return false;
   }
 
-  public boolean isUDAFExpression() {
+  public boolean isUserDefinedAggregationFunctionExpression() {
     return false;
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java
index f5e1d23..c30e56f 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java
@@ -69,15 +69,15 @@ public abstract class BinaryExpression extends Expression {
 
   @Override
   public boolean isTimeSeriesGeneratingFunctionExpression() {
-    return !isUDAFExpression();
+    return !isUserDefinedAggregationFunctionExpression();
   }
 
   @Override
-  public boolean isUDAFExpression() {
-    return leftExpression.isAggregationFunctionExpression()
-        || rightExpression.isAggregationFunctionExpression()
-        || leftExpression.isUDAFExpression()
-        || rightExpression.isUDAFExpression();
+  public boolean isUserDefinedAggregationFunctionExpression() {
+    return leftExpression.isPlainAggregationFunctionExpression()
+        || rightExpression.isPlainAggregationFunctionExpression()
+        || leftExpression.isUserDefinedAggregationFunctionExpression()
+        || rightExpression.isUserDefinedAggregationFunctionExpression();
   }
 
   @Override
diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java
index 885f2bd..cb18570 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java
@@ -60,9 +60,9 @@ public class FunctionExpression extends Expression {
    * true: aggregation function<br>
    * false: time series generating function
    */
-  private final boolean isAggregationFunctionExpression;
+  private final boolean isPlainAggregationFunctionExpression;
 
-  private boolean isUDAFExpression;
+  private boolean isUserDefinedAggregationFunctionExpression;
 
   private final String functionName;
   private final Map<String, String> functionAttributes;
@@ -82,7 +82,7 @@ public class FunctionExpression extends Expression {
     this.functionName = functionName;
     functionAttributes = new LinkedHashMap<>();
     expressions = new ArrayList<>();
-    isAggregationFunctionExpression =
+    isPlainAggregationFunctionExpression =
         SQLConstant.getNativeFunctionNames().contains(functionName.toLowerCase());
     isConstantOperandCache = true;
   }
@@ -92,17 +92,20 @@ public class FunctionExpression extends Expression {
     this.functionName = functionName;
     this.functionAttributes = functionAttributes;
     this.expressions = expressions;
-    isAggregationFunctionExpression =
+    isPlainAggregationFunctionExpression =
         SQLConstant.getNativeFunctionNames().contains(functionName.toLowerCase());
     isConstantOperandCache = expressions.stream().anyMatch(Expression::isConstantOperand);
-    isUDAFExpression =
+    isUserDefinedAggregationFunctionExpression =
         expressions.stream()
-            .anyMatch(v -> v.isUDAFExpression() || v.isAggregationFunctionExpression());
+            .anyMatch(
+                v ->
+                    v.isUserDefinedAggregationFunctionExpression()
+                        || v.isPlainAggregationFunctionExpression());
   }
 
   @Override
-  public boolean isAggregationFunctionExpression() {
-    return isAggregationFunctionExpression;
+  public boolean isPlainAggregationFunctionExpression() {
+    return isPlainAggregationFunctionExpression;
   }
 
   @Override
@@ -111,13 +114,13 @@ public class FunctionExpression extends Expression {
   }
 
   @Override
-  public boolean isUDAFExpression() {
-    return isUDAFExpression;
+  public boolean isTimeSeriesGeneratingFunctionExpression() {
+    return !isPlainAggregationFunctionExpression() && !isUserDefinedAggregationFunctionExpression();
   }
 
   @Override
-  public boolean isTimeSeriesGeneratingFunctionExpression() {
-    return !isAggregationFunctionExpression;
+  public boolean isUserDefinedAggregationFunctionExpression() {
+    return isUserDefinedAggregationFunctionExpression;
   }
 
   public boolean isCountStar() {
@@ -132,10 +135,10 @@ public class FunctionExpression extends Expression {
 
   public void addExpression(Expression expression) {
     isConstantOperandCache = isConstantOperandCache && expression.isConstantOperand();
-    isUDAFExpression =
-        isUDAFExpression
-            || expression.isUDAFExpression()
-            || expression.isAggregationFunctionExpression();
+    isUserDefinedAggregationFunctionExpression =
+        isUserDefinedAggregationFunctionExpression
+            || expression.isUserDefinedAggregationFunctionExpression()
+            || expression.isPlainAggregationFunctionExpression();
     expressions.add(expression);
   }
 
@@ -151,6 +154,7 @@ public class FunctionExpression extends Expression {
     return functionAttributes;
   }
 
+  @Override
   public List<Expression> getExpressions() {
     return expressions;
   }
@@ -224,7 +228,7 @@ public class FunctionExpression extends Expression {
     if (!expressionIntermediateLayerMap.containsKey(this)) {
       float memoryBudgetInMB = memoryAssigner.assign();
       Transformer transformer;
-      if (isAggregationFunctionExpression) {
+      if (isPlainAggregationFunctionExpression) {
         transformer =
             new TransparentTransformer(
                 rawTimeSeriesInputLayer.constructPointReader(
diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/NegationExpression.java b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/NegationExpression.java
index ced0532..43c6dc5 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/NegationExpression.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/NegationExpression.java
@@ -67,12 +67,13 @@ public class NegationExpression extends Expression {
 
   @Override
   public boolean isTimeSeriesGeneratingFunctionExpression() {
-    return true;
+    return !isUserDefinedAggregationFunctionExpression();
   }
 
   @Override
-  public boolean isUDAFExpression() {
-    return expression.isUDAFExpression() || expression.isAggregationFunctionExpression();
+  public boolean isUserDefinedAggregationFunctionExpression() {
+    return expression.isUserDefinedAggregationFunctionExpression()
+        || expression.isPlainAggregationFunctionExpression();
   }
 
   @Override