This is an automated email from the ASF dual-hosted git repository.
JackieTien97 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 edd5a74c42d Prevent query with explict limit 0 (#18858)
edd5a74c42d is described below
commit edd5a74c42dcfa4076b8b07b619defe280dfd66b
Author: Weihao Li <[email protected]>
AuthorDate: Wed Oct 14 15:16:47 2026 +0800
Prevent query with explict limit 0 (#18858)
---
.../it/query/old/IoTDBSimpleQueryTableIT.java | 24 +++++++
.../query/view/recent/IoTDBTableViewQueryIT.java | 2 +-
.../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 +++-----
10 files changed, 87 insertions(+), 110 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/query/view/recent/IoTDBTableViewQueryIT.java
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/view/recent/IoTDBTableViewQueryIT.java
index e763da925f9..cec9028edb2 100644
---
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/view/recent/IoTDBTableViewQueryIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/view/recent/IoTDBTableViewQueryIT.java
@@ -340,7 +340,7 @@ public class IoTDBTableViewQueryIT {
true);
// empty result
compareQueryResults(
- session, "select * from view3 limit 1", "select * from table1 limit
0", true);
+ session, "select * from view3 limit 1", "select * from table1 where
battery = 'b'", true);
// not exists
compareQueryResults(
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)");
}
}