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/06/29 12:36:48 UTC
[iotdb] branch rel/1.1 updated: [To rel/1.1] Fix error sql when using raw query and align by device with having clause
This is an automated email from the ASF dual-hosted git repository.
jackietien pushed a commit to branch rel/1.1
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/rel/1.1 by this push:
new f1fb782e76c [To rel/1.1] Fix error sql when using raw query and align by device with having clause
f1fb782e76c is described below
commit f1fb782e76cad10516d047cf487cf5e7455a5c3c
Author: Beyyes <cg...@foxmail.com>
AuthorDate: Thu Jun 29 20:36:41 2023 +0800
[To rel/1.1] Fix error sql when using raw query and align by device with having clause
---
.../db/mpp/plan/statement/crud/QueryStatement.java | 14 +-
.../db/mpp/plan/statement/QueryStatementTest.java | 148 +++++++++++++++++++++
2 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
index 7ffb1b7299f..9e06d677962 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
@@ -465,8 +465,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());
}
@@ -483,9 +488,16 @@ public class QueryStatement extends Statement {
for (ResultColumn resultColumn : selectComponent.getResultColumns()) {
ExpressionAnalyzer.checkIsAllMeasurement(resultColumn.getExpression());
}
+ if (hasGroupByExpression()) {
+ ExpressionAnalyzer.checkIsAllMeasurement(
+ getGroupByComponent().getControlColumnExpression());
+ }
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/server/src/test/java/org/apache/iotdb/db/mpp/plan/statement/QueryStatementTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/plan/statement/QueryStatementTest.java
new file mode 100644
index 00000000000..acc2d45d09f
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/plan/statement/QueryStatementTest.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.mpp.plan.statement;
+
+import org.apache.iotdb.db.exception.sql.SemanticException;
+import org.apache.iotdb.db.mpp.plan.parser.StatementGenerator;
+import org.apache.iotdb.db.mpp.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.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 data and aggregation hybrid query is not supported."),
+
+ // 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 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());
+ continue;
+ } catch (Exception ex) {
+ fail(String.format("Meets exception %s in test sql: `%s`", errorMsg, errorSql));
+ }
+ fail(String.format("Sql: `%s` must throw exception: %s", errorSql, errorMsg));
+ }
+ }
+
+ private void checkErrorQuerySql(String sql) {
+ QueryStatement statement =
+ (QueryStatement) StatementGenerator.createStatement(sql, ZonedDateTime.now().getOffset());
+ statement.semanticCheck();
+ }
+}