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 37a66a68858 Fix error sql when using `raw query` and `align by device` 
with having clause (#10360)
37a66a68858 is described below

commit 37a66a68858e711741c753cafb9d009087a48409
Author: Beyyes <[email protected]>
AuthorDate: Thu Jun 29 14:31:36 2023 +0800

    Fix error sql when using `raw query` and `align by device` with having 
clause (#10360)
---
 .../plan/statement/crud/QueryStatement.java        |  12 +-
 .../plan/statement/QueryStatementTest.java         | 150 +++++++++++++++++++++
 2 files changed, 160 insertions(+), 2 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/QueryStatement.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/QueryStatement.java
index 8e575156a9a..6e8f8964591 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/QueryStatement.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/QueryStatement.java
@@ -469,7 +469,7 @@ public class QueryStatement extends Statement {
     return useWildcard;
   }
 
-  private static final String RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG =
+  public static final String RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG =
       "Raw data and aggregation hybrid query is not supported.";
 
   public void semanticCheck() {
@@ -549,8 +549,13 @@ public class QueryStatement extends Statement {
           != ResultColumn.ColumnType.AGGREGATION) {
         throw new SemanticException("Expression of HAVING clause must to be an 
Aggregation");
       }
+      if (!isAggregationQuery()) {
+        throw new SemanticException(
+            "Expression of HAVING clause can not be used in 
NonAggregationQuery");
+      }
       try {
-        if (isGroupByLevel()) { // check path in SELECT and HAVING only have 
one node
+        if (isGroupByLevel()) {
+          // check path in SELECT and HAVING only have one node
           for (ResultColumn resultColumn : 
getSelectComponent().getResultColumns()) {
             
ExpressionAnalyzer.checkIsAllMeasurement(resultColumn.getExpression());
           }
@@ -579,6 +584,9 @@ public class QueryStatement extends Statement {
         if (getWhereCondition() != null) {
           
ExpressionAnalyzer.checkIsAllMeasurement(getWhereCondition().getPredicate());
         }
+        if (hasHaving()) {
+          
ExpressionAnalyzer.checkIsAllMeasurement(getHavingCondition().getPredicate());
+        }
       } catch (SemanticException e) {
         throw new SemanticException("ALIGN BY DEVICE: " + e.getMessage());
       }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/QueryStatementTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/QueryStatementTest.java
new file mode 100644
index 00000000000..13bf64cd62a
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/statement/QueryStatementTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.queryengine.plan.statement;
+
+import org.apache.iotdb.db.exception.sql.SemanticException;
+import org.apache.iotdb.db.queryengine.plan.parser.StatementGenerator;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.ZonedDateTime;
+import java.util.Arrays;
+import java.util.List;
+
+import static 
org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement.RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class QueryStatementTest {
+
+  private static final Logger logger = 
LoggerFactory.getLogger(QueryStatementTest.class);
+
+  private static final String ALIGN_BY_DEVICE_ONE_LEVEL_ERROR =
+      "ALIGN BY DEVICE: the suffix paths can only be measurement or one-level 
wildcard";
+
+  @Test
+  public void semanticCheckTest() {
+    List<Pair<String, String>> errorSqlWithMessages =
+        Arrays.asList(
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 "
+                    + "GROUP BY ([2017-11-01T00:00:00, 
2017-11-07T23:00:00),1d)",
+                "Common queries and aggregated queries are not allowed to 
appear at the same time"),
+            new Pair<>(
+                "SELECT count(s1),s2 FROM root.sg.d1", 
RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG),
+
+            // test for where clause
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 WHERE count(s1) > 0",
+                "aggregate functions are not supported in WHERE clause"),
+
+            // test for having clause
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 HAVING(s1 > 0)",
+                "Expression of HAVING clause must to be an Aggregation"),
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 HAVING(count(s1) > 0)",
+                "Expression of HAVING clause can not be used in 
NonAggregationQuery"),
+            new Pair<>(
+                "SELECT count(d1.s1) FROM root.sg.d1 GROUP BY level=1 HAVING 
(count(s1) > 0)",
+                "When Having used with GroupByLevel: "
+                    + "the suffix paths can only be measurement or one-level 
wildcard"),
+            new Pair<>(
+                "SELECT count(s1) FROM root.sg.d1 GROUP BY level=1 HAVING 
(count(sg.d1.s1) > 0)",
+                "When Having used with GroupByLevel: "
+                    + "the suffix paths can only be measurement or one-level 
wildcard"),
+
+            // test for align by device clause
+            new Pair<>(
+                "SELECT d1.s1 FROM root.sg.d1 align by device", 
ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
+            new Pair<>(
+                "SELECT count(s1) FROM root.sg.d1 group by variation(sg.s1) 
align by device",
+                ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 order by root.sg.d1.s1 align by 
device",
+                ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 where root.sg.d1.s1 > 0 align by 
device",
+                ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
+            new Pair<>(
+                "SELECT count(s1) FROM root.sg.d1 having(count(root.sg.d1.s1) 
> 0) align by device",
+                ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 order by timeseries align by 
device",
+                "Sorting by timeseries is only supported in last queries."),
+
+            // test for last query
+            new Pair<>(
+                "SELECT last s1 FROM root.sg.d1 align by device",
+                "Last query doesn't support align by device."),
+            new Pair<>(
+                "SELECT last s1+s2 FROM root.sg.d1",
+                "Last queries can only be applied on raw time series."),
+            new Pair<>(
+                "SELECT last s1 FROM root.sg.d1 order by device",
+                "Sorting by device is only supported in ALIGN BY DEVICE 
queries."),
+            new Pair<>(
+                "SELECT last s1 FROM root.sg.d1 SLIMIT 1 SOFFSET 2",
+                "SLIMIT and SOFFSET can not be used in LastQuery."),
+
+            // test for select into clause
+            new Pair<>(
+                "SELECT s1 INTO root.sg.d2(t1) FROM root.sg.d1 SLIMIT 5",
+                "select into: slimit clauses are not supported."),
+            new Pair<>(
+                "SELECT s1 INTO root.sg.d2(t1) FROM root.sg.d1 SOFFSET 6",
+                "select into: soffset clauses are not supported."),
+            new Pair<>(
+                "SELECT last s1 INTO root.sg.d2(t1) FROM root.sg.d1",
+                "select into: last clauses are not supported."),
+            new Pair<>(
+                "SELECT count(s1) INTO root.sg.d2(t1) FROM root.sg.d1 GROUP BY 
TAGS(a)",
+                "select into: GROUP BY TAGS clause are not supported."),
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 order by timeseries",
+                "Sorting by timeseries is only supported in last queries."),
+            new Pair<>(
+                "SELECT s1 FROM root.sg.d1 order by device",
+                "Sorting by device is only supported in ALIGN BY DEVICE 
queries."));
+
+    for (Pair<String, String> pair : errorSqlWithMessages) {
+      String errorSql = pair.left;
+      String errorMsg = pair.right;
+      try {
+        checkErrorQuerySql(errorSql);
+      } catch (SemanticException e) {
+        assertEquals(errorMsg, e.getMessage());
+      } catch (Exception ex) {
+        logger.error("Meets error in test sql: {}", errorSql, ex);
+        fail();
+      }
+    }
+  }
+
+  private void checkErrorQuerySql(String sql) {
+    QueryStatement statement =
+        (QueryStatement) StatementGenerator.createStatement(sql, 
ZonedDateTime.now().getOffset());
+    statement.semanticCheck();
+  }
+}

Reply via email to