You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by we...@apache.org on 2026/10/14 02:43:30 UTC
(iotdb) 01/01: fix
This is an automated email from the ASF dual-hosted git repository.
Wei-hao-Li pushed a commit to branch fixLimit0
in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit aca66c88e4d4db7fb904a4dfa6e521f44856b147
Author: Weihao Li <18...@163.com>
AuthorDate: Wed Oct 14 10:43:10 2026 +0800
fix
Signed-off-by: Weihao Li <18...@163.com>
---
.../it/query/old/IoTDBSimpleQueryTableIT.java | 24 +++++++
.../iotdb/relational/it/schema/IoTDBDeviceIT.java | 13 ++--
.../iotdb/db/i18n/DataNodeQueryMessages.java | 5 +-
.../iotdb/db/i18n/DataNodeQueryMessages.java | 5 +-
.../relational/analyzer/StatementAnalyzer.java | 4 +-
.../plan/relational/analyzer/AnalyzerTest.java | 9 +++
.../analyzer/EvaluateEmptyIntersectTest.java | 25 ++-----
.../analyzer/RemoveEmptyExceptBranchesTest.java | 82 +++++-----------------
.../relational/analyzer/UnionOptimizeTest.java | 28 +++-----
9 files changed, 86 insertions(+), 109 deletions(-)
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/IoTDBSimpleQueryTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/IoTDBSimpleQueryTableIT.java
index f8cc92699e7..47e7655ff44 100644
--- a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/IoTDBSimpleQueryTableIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/IoTDBSimpleQueryTableIT.java
@@ -95,6 +95,30 @@ public class IoTDBSimpleQueryTableIT {
}
}
+ @Test
+ public void testLimitZeroRejected() throws SQLException {
+ try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT);
+ Statement statement = connection.createStatement()) {
+ statement.execute("CREATE DATABASE " + DATABASE_NAME);
+ statement.execute("USE " + DATABASE_NAME);
+ statement.execute("CREATE TABLE table1(device STRING TAG, s1 INT32 FIELD)");
+
+ assertLimitZeroRejected(statement, "SELECT * FROM table1 LIMIT 0");
+ assertLimitZeroRejected(statement, "SELECT * FROM table1 ORDER BY time LIMIT 0");
+ }
+ }
+
+ private static void assertLimitZeroRejected(Statement statement, String sql) {
+ try {
+ statement.executeQuery(sql);
+ fail("Expected LIMIT 0 to be rejected");
+ } catch (SQLException e) {
+ assertTrue(
+ e.getMessage(),
+ e.getMessage().contains("LIMIT row count must be greater than 0 (actual value: 0)"));
+ }
+ }
+
@Ignore // TODO After last query supported
@Test
public void testLastQueryNonCached() {
diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDeviceIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDeviceIT.java
index 1eb2da9d100..75bf4646a50 100644
--- a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDeviceIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBDeviceIT.java
@@ -38,6 +38,7 @@ import java.sql.Statement;
import java.util.Collections;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@RunWith(IoTDBTestRunner.class)
@@ -106,10 +107,14 @@ public class IoTDBDeviceIT {
"show devices from table0 where region_id < plant_id offset 0 limit 1"),
"region_id,plant_id,device_id,model,",
Collections.singleton("1,木兰,3,A,"));
- TestUtils.assertResultSetEqual(
- statement.executeQuery("show devices from table0 where region_id < plant_id limit 0"),
- "region_id,plant_id,device_id,model,",
- Collections.emptySet());
+ try {
+ statement.executeQuery("show devices from table0 where region_id < plant_id limit 0");
+ fail("Expected LIMIT 0 to be rejected");
+ } catch (SQLException e) {
+ assertTrue(
+ e.getMessage(),
+ e.getMessage().contains("LIMIT row count must be greater than 0 (actual value: 0)"));
+ }
TestUtils.assertResultSetEqual(
statement.executeQuery("count devices from table0 where region_id < plant_id"),
"count(devices),",
diff --git a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
index 73b27b06223..b030af64cfa 100644
--- a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
+++ b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
@@ -2261,8 +2261,9 @@ public final class DataNodeQueryMessages {
"Type %s is not orderable, and therefore cannot be used in ORDER BY: %s";
public static final String OFFSET_ROW_COUNT_MUST_BE_GREATER_OR_EQUAL_TO_0_ACTUAL_VALUE_S =
"OFFSET row count must be greater or equal to 0 (actual value: %s)";
- public static final String LIMIT_ROW_COUNT_MUST_BE_GREATER_OR_EQUAL_TO_0_ACTUAL_VALUE_S =
- "LIMIT row count must be greater or equal to 0 (actual value: %s)";
+ public static final String
+ EXCEPTION_LIMIT_ROW_COUNT_MUST_BE_GREATER_THAN_0_ACTUAL_VALUE_ARG_79F8F1A3 =
+ "LIMIT row count must be greater than 0 (actual value: %s)";
public static final String NON_CONSTANT_PARAMETER_VALUE_FOR_S_S =
"Non constant parameter value for %s: %s";
public static final String PARAMETER_VALUE_PROVIDED_FOR_S_IS_NULL_S =
diff --git a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
index ed1fefe479a..5a504e2a017 100644
--- a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
+++ b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodeQueryMessages.java
@@ -2518,9 +2518,10 @@ public final class DataNodeQueryMessages {
public static final String OFFSET_ROW_COUNT_MUST_BE_GREATER_OR_EQUAL_TO_0_ACTUAL_VALUE_S =
"OFFSET 行数必须大于或等于 0(实际值:%s)";
- public static final String LIMIT_ROW_COUNT_MUST_BE_GREATER_OR_EQUAL_TO_0_ACTUAL_VALUE_S =
+ public static final String
+ EXCEPTION_LIMIT_ROW_COUNT_MUST_BE_GREATER_THAN_0_ACTUAL_VALUE_ARG_79F8F1A3 =
- "LIMIT 行数必须大于或等于 0(实际值:%s)";
+ "LIMIT 行数必须大于 0(实际值:%s)";
public static final String NON_CONSTANT_PARAMETER_VALUE_FOR_S_S =
"%s 的参数值不是常量:%s";
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
index 88f605f6dfd..e1c9db8d0f2 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/StatementAnalyzer.java
@@ -5058,11 +5058,11 @@ public class StatementAnalyzer {
}
rowCount.ifPresent(
count -> {
- if (count < 0) {
+ if (count <= 0) {
throw new SemanticException(
String.format(
DataNodeQueryMessages
- .LIMIT_ROW_COUNT_MUST_BE_GREATER_OR_EQUAL_TO_0_ACTUAL_VALUE_S,
+ .EXCEPTION_LIMIT_ROW_COUNT_MUST_BE_GREATER_THAN_0_ACTUAL_VALUE_ARG_79F8F1A3,
count));
}
});
diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
index 5cc6261b4a6..9c9918ddbc8 100644
--- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
+++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java
@@ -182,6 +182,15 @@ public class AnalyzerTest {
IoTDBDescriptor.getInstance().getConfig().setDataNodeId(1);
}
+ @Test
+ public void testLimitZeroRejected() {
+ TestUtils.assertAnalyzeSemanticException(
+ "SELECT * FROM table1 LIMIT 0", "LIMIT row count must be greater than 0 (actual value: 0)");
+ TestUtils.assertAnalyzeSemanticException(
+ "SELECT * FROM table1 ORDER BY time LIMIT 0",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
+ }
+
@Test
public void testMockQuery() throws OperatorNotFoundException {
final String sql =
diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/EvaluateEmptyIntersectTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/EvaluateEmptyIntersectTest.java
index a69b4af288c..3464ffcbc20 100644
--- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/EvaluateEmptyIntersectTest.java
+++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/EvaluateEmptyIntersectTest.java
@@ -19,30 +19,19 @@
package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
-import org.apache.iotdb.db.queryengine.plan.relational.planner.PlanTester;
-
import org.junit.Test;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanAssert.assertPlan;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.limit;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.output;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.tableScan;
+import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils.assertAnalyzeSemanticException;
public class EvaluateEmptyIntersectTest {
@Test
public void EvaluateEmptyIntersectTest() {
- // Normal case
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1 limit 0) intersect (select tag1 from t2) intersect (select tag1 from t3)"),
- output((limit(0, tableScan("testdb.t1")))));
-
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1 ) intersect all (select tag1 from t2 limit 0) intersect all (select tag1 from t3)"),
- output((limit(0, tableScan("testdb.t2")))));
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1 limit 0) intersect (select tag1 from t2) intersect (select tag1 from t3)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1) intersect all (select tag1 from t2 limit 0) intersect all (select tag1 from t3)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
}
}
diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/RemoveEmptyExceptBranchesTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/RemoveEmptyExceptBranchesTest.java
index 914a9bdae0b..9602aaeb29c 100644
--- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/RemoveEmptyExceptBranchesTest.java
+++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/RemoveEmptyExceptBranchesTest.java
@@ -19,83 +19,39 @@
package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
-import org.apache.iotdb.db.queryengine.plan.relational.planner.PlanTester;
-
import org.junit.Test;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanAssert.assertPlan;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.aggregation;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.filter;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.limit;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.output;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.project;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.sort;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.tableScan;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.union;
-import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.window;
+import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils.assertAnalyzeSemanticException;
public class RemoveEmptyExceptBranchesTest {
@Test
public void removeEmptyExceptBranchesTest1() {
- // Normal case
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1 limit 0) except (select tag1 from t2) except (select tag1 from t3)"),
- output((limit(0, tableScan("testdb.t1")))));
-
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1 limit 0) except all (select tag1 from t2) except all (select tag1 from t3)"),
- output((limit(0, tableScan("testdb.t1")))));
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1 limit 0) except (select tag1 from t2) except (select tag1 from t3)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1 limit 0) except all (select tag1 from t2) except all (select tag1 from t3)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
}
@Test
public void removeEmptyExceptBranchesTest2() {
- // Normal case
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1 ) except (select tag1 from t2 limit 0) except (select tag1 from t3 limit 0)"),
- output(aggregation(tableScan("testdb.t1"))));
-
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1) except all (select tag1 from t2 limit 0) except all (select tag1 from t3 limit 0)"),
- output((tableScan("testdb.t1"))));
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1) except (select tag1 from t2 limit 0) except (select tag1 from t3 limit 0)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1) except all (select tag1 from t2 limit 0) except all (select tag1 from t3 limit 0)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
}
@Test
public void removeEmptyExceptBranchesTest3() {
- // Normal case
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1) except (select tag1 from t2) except (select tag1 from t3 limit 0)"),
- output(
- aggregation(
- project(
- filter(
- aggregation(
- union(
- project(tableScan("testdb.t1")),
- project(tableScan("testdb.t2")))))))));
-
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1) except all (select tag1 from t2 ) except all (select tag1 from t3 limit 0)"),
- output(
- project(
- filter(
- project(
- window(
- sort(
- union(
- project(tableScan("testdb.t1")),
- project(tableScan("testdb.t2"))))))))));
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1) except (select tag1 from t2) except (select tag1 from t3 limit 0)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1) except all (select tag1 from t2) except all (select tag1 from t3 limit 0)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
}
}
diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/UnionOptimizeTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/UnionOptimizeTest.java
index 4fdbdb27b3d..f55b357051d 100644
--- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/UnionOptimizeTest.java
+++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/UnionOptimizeTest.java
@@ -31,6 +31,7 @@ import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils.QUERY_CONTEXT;
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils.SESSION_INFO;
import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils.TEST_MATADATA;
+import static org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils.assertAnalyzeSemanticException;
import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanAssert.assertPlan;
import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.limit;
import static org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.output;
@@ -128,31 +129,22 @@ public class UnionOptimizeTest {
@Test
public void removeEmptyUnionBranchesTest1() {
- // Normal case
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1 limit 0) union all (select tag1 from t2) union all (select tag1 from t3)"),
- output((union(tableScan("testdb.t2"), tableScan("testdb.t3")))));
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1 limit 0) union all (select tag1 from t2) union all (select tag1 from t3)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
}
@Test
public void removeEmptyUnionBranchesTest2() {
- // One non-empty branch
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1 limit 0) union all (select tag1 from t2 limit 0) union all (select tag1 from t3 limit 1)"),
- output(limit(1, tableScan("testdb.t3"))));
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1 limit 0) union all (select tag1 from t2 limit 0) union all (select tag1 from t3 limit 1)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
}
@Test
public void removeEmptyUnionBranchesTest3() {
- // All branches are empty
- assertPlan(
- new PlanTester()
- .createPlan(
- "(select tag1 from t1 limit 0) union all (select tag1 from t2 limit 0) union all (select tag1 from t3 limit 0)"),
- output(limit(0, tableScan("testdb.t1"))));
+ assertAnalyzeSemanticException(
+ "(select tag1 from t1 limit 0) union all (select tag1 from t2 limit 0) union all (select tag1 from t3 limit 0)",
+ "LIMIT row count must be greater than 0 (actual value: 0)");
}
}