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 <[email protected]>
AuthorDate: Wed Oct 14 10:43:10 2026 +0800

    fix
    
    Signed-off-by: Weihao Li <[email protected]>
---
 .../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)");
   }
 }

Reply via email to