You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by hu...@apache.org on 2023/03/14 07:15:35 UTC
[iotdb] branch rel/1.1 updated: [IOTDB-5657] Fix LIMIT&OFFSET does not take effect in last query (#9309) (#9312)
This is an automated email from the ASF dual-hosted git repository.
hui 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 02c3aed10d [IOTDB-5657] Fix LIMIT&OFFSET does not take effect in last query (#9309) (#9312)
02c3aed10d is described below
commit 02c3aed10dc6d9aa151c9bf9766f3586c794dfbe
Author: Liao Lanyu <14...@qq.com>
AuthorDate: Tue Mar 14 15:15:30 2023 +0800
[IOTDB-5657] Fix LIMIT&OFFSET does not take effect in last query (#9309) (#9312)
---
.../it/last/IoTDBLastQueryWithLimitOffsetIT.java | 193 +++++++++++++++++++++
.../mpp/plan/optimization/LimitOffsetPushDown.java | 3 +-
.../db/mpp/plan/planner/LogicalPlanVisitor.java | 2 +
.../db/mpp/plan/statement/crud/QueryStatement.java | 3 +
4 files changed, 200 insertions(+), 1 deletion(-)
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryWithLimitOffsetIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryWithLimitOffsetIT.java
new file mode 100644
index 0000000000..e86760c9e4
--- /dev/null
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/last/IoTDBLastQueryWithLimitOffsetIT.java
@@ -0,0 +1,193 @@
+/*
+ * 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.last;
+
+import org.apache.iotdb.db.mpp.common.header.ColumnHeaderConstant;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.ClusterIT;
+import org.apache.iotdb.itbase.category.LocalStandaloneIT;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({LocalStandaloneIT.class, ClusterIT.class})
+public class IoTDBLastQueryWithLimitOffsetIT {
+ @BeforeClass
+ public static void setUp() throws Exception {
+ EnvFactory.getEnv().initClusterEnvironment();
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute("insert into root.sg.d1(time, s1, s2) values(1, 1, 1)");
+ statement.execute("insert into root.sg.d2(time, s1, s2) aligned values(2, 1, 1)");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ EnvFactory.getEnv().cleanClusterEnvironment();
+ }
+
+ @Test
+ public void testWithLimit() {
+ String[] retArray =
+ new String[] {
+ "1,root.sg.d1.s1,1.0,FLOAT",
+ };
+
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+
+ try (ResultSet resultSet =
+ statement.executeQuery("select last * from root.sg.* order by timeseries asc limit 1")) {
+ int cnt = 0;
+ while (resultSet.next()) {
+ String ans =
+ resultSet.getString(ColumnHeaderConstant.TIME)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.TIMESERIES)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.VALUE)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.DATATYPE);
+ assertEquals(retArray[cnt++], ans);
+ }
+ assertEquals(retArray.length, cnt);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testWithOffset() {
+ String[] retArray = new String[] {"2,root.sg.d2.s2,1.0,FLOAT"};
+
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+
+ try (ResultSet resultSet =
+ statement.executeQuery("select last * from root.sg.* order by timeseries asc offset 3")) {
+ int cnt = 0;
+ while (resultSet.next()) {
+ String ans =
+ resultSet.getString(ColumnHeaderConstant.TIME)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.TIMESERIES)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.VALUE)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.DATATYPE);
+ assertEquals(retArray[cnt++], ans);
+ }
+ assertEquals(retArray.length, cnt);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testWithLimitAndOffset() {
+ String[] retArray =
+ new String[] {
+ "1,root.sg.d1.s2,1.0,FLOAT", "2,root.sg.d2.s1,1.0,FLOAT",
+ };
+
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+
+ try (ResultSet resultSet =
+ statement.executeQuery(
+ "select last * from root.sg.* order by timeseries asc limit 2 offset 1")) {
+ int cnt = 0;
+ while (resultSet.next()) {
+ String ans =
+ resultSet.getString(ColumnHeaderConstant.TIME)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.TIMESERIES)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.VALUE)
+ + ","
+ + resultSet.getString(ColumnHeaderConstant.DATATYPE);
+ assertEquals(retArray[cnt++], ans);
+ }
+ assertEquals(retArray.length, cnt);
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testWithSLimitOrSOffset() {
+
+ try (Connection connection = EnvFactory.getEnv().getConnection();
+ Statement statement = connection.createStatement()) {
+
+ try {
+ statement.executeQuery("select last * from root.sg.* order by timeseries asc slimit 1");
+ fail();
+ } catch (Exception ignored) {
+
+ }
+
+ try {
+ statement.executeQuery("select last * from root.sg.* order by timeseries asc soffset 1");
+ fail();
+ } catch (Exception ignored) {
+
+ }
+
+ try {
+ statement.executeQuery(
+ "select last * from root.sg.* order by timeseries asc slimit 1 soffset 1");
+ fail();
+ } catch (Exception ignored) {
+
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/optimization/LimitOffsetPushDown.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/optimization/LimitOffsetPushDown.java
index a2b55ca175..5e9952c1ad 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/optimization/LimitOffsetPushDown.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/optimization/LimitOffsetPushDown.java
@@ -59,7 +59,8 @@ public class LimitOffsetPushDown implements PlanOptimizer {
return plan;
}
QueryStatement queryStatement = (QueryStatement) analysis.getStatement();
- if (queryStatement.isAggregationQuery()
+ if (queryStatement.isLastQuery()
+ || queryStatement.isAggregationQuery()
|| (!queryStatement.hasLimit() && !queryStatement.hasOffset())) {
return plan;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanVisitor.java
index a5453c348b..5e503cb6c6 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanVisitor.java
@@ -115,6 +115,8 @@ public class LogicalPlanVisitor extends StatementVisitor<PlanNode, MPPQueryConte
analysis.getSourceExpressions(),
analysis.getGlobalTimeFilter(),
analysis.getMergeOrderParameter())
+ .planOffset(queryStatement.getRowOffset())
+ .planLimit(queryStatement.getRowLimit())
.getRoot();
}
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 810586dc29..2be3358e20 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
@@ -505,6 +505,9 @@ public class QueryStatement extends Statement {
if (isOrderByTime()) {
throw new SemanticException("Sorting by time is not yet supported in last queries.");
}
+ if (seriesLimit != 0 || seriesOffset != 0) {
+ throw new SemanticException("SLIMIT and SOFFSET can not be used in LastQuery.");
+ }
}
if (!isAlignByDevice() && !isLastQuery()) {