This is an automated email from the ASF dual-hosted git repository.

jackietien pushed a commit to branch force_ci/object_type
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 0fc8e176e72f2341f82cf69750dc22b15d5cee15
Author: Jackie Tien <[email protected]>
AuthorDate: Tue Nov 4 16:40:50 2025 +0800

    Fix wrong push limit down to AggTableScanNode (#16696)
    
    (cherry picked from commit 8420beaaf5470b695c5d2afcb7491d226a7a8202)
---
 .../relational/it/query/recent/IoTDBTableAggregationIT.java | 13 +++++++++++++
 .../planner/distribute/TableDistributedPlanGenerator.java   |  2 +-
 .../planner/iterative/rule/PushDownOffsetIntoTableScan.java |  4 +++-
 .../relational/planner/node/AggregationTableScanNode.java   | 10 ++++++++++
 .../planner/optimizations/PushLimitOffsetIntoTableScan.java |  2 +-
 5 files changed, 28 insertions(+), 3 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableAggregationIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableAggregationIT.java
index 0143bdb6e3b..88367283eb7 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableAggregationIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableAggregationIT.java
@@ -5491,4 +5491,17 @@ public class IoTDBTableAggregationIT {
         retArray,
         DATABASE_NAME);
   }
+
+  @Test
+  public void orderByLimitTest() {
+    String[] expectedHeader =
+        new String[] {"province", "city", "region", "device_id", "_col4", 
"_col5"};
+    String[] retArray = new String[] 
{"beijing,beijing,chaoyang,d09,2024-09-24T06:00:00.000Z,2,"};
+
+    tableResultSetEqualTest(
+        "select province, city, region, device_id, date_bin(1h, time), 
count(s1) from table1 where s1 >= 40 group by 1,2,3,4,5 order by province, 
city, region, device_id, date_bin(1h, time) limit 1",
+        expectedHeader,
+        retArray,
+        DATABASE_NAME);
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableDistributedPlanGenerator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableDistributedPlanGenerator.java
index 850ef0a81e3..069d1df7469 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableDistributedPlanGenerator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/distribute/TableDistributedPlanGenerator.java
@@ -423,7 +423,7 @@ public class TableDistributedPlanGenerator
   private boolean canTopKEliminated(OrderingScheme orderingScheme, long k, 
PlanNode child) {
     // if DeviceTableScanNode has limit <= K and with same order, we can 
directly return
     // DeviceTableScanNode
-    if (child instanceof DeviceTableScanNode) {
+    if (child instanceof DeviceTableScanNode && !(child instanceof 
AggregationTableScanNode)) {
       DeviceTableScanNode tableScanNode = (DeviceTableScanNode) child;
       if (canSortEliminated(orderingScheme, 
nodeOrderingMap.get(child.getPlanNodeId()))) {
         if (tableScanNode.getPushDownLimit() <= 0) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushDownOffsetIntoTableScan.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushDownOffsetIntoTableScan.java
index d683dbe3fdb..77143f90374 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushDownOffsetIntoTableScan.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PushDownOffsetIntoTableScan.java
@@ -20,6 +20,7 @@
 package org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule;
 
 import org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.Rule;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.AggregationTableScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.DeviceTableScanNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OffsetNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode;
@@ -53,7 +54,8 @@ public class PushDownOffsetIntoTableScan implements 
Rule<OffsetNode> {
   @Override
   public Result apply(OffsetNode parent, Captures captures, Context context) {
     TableScanNode tableScanNode = captures.get(CHILD);
-    if (tableScanNode instanceof DeviceTableScanNode
+    if ((tableScanNode instanceof DeviceTableScanNode
+            && !(tableScanNode instanceof AggregationTableScanNode))
         && !((DeviceTableScanNode) tableScanNode).isPushLimitToEachDevice()) {
       tableScanNode.setPushDownOffset(parent.getCount());
       // consider case that there is no limit
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/AggregationTableScanNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/AggregationTableScanNode.java
index b6840d7200a..56d39f2f77d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/AggregationTableScanNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/AggregationTableScanNode.java
@@ -623,4 +623,14 @@ public class AggregationTableScanNode extends 
DeviceTableScanNode {
   public Map<DeviceEntry, Integer> getDeviceCountMap() {
     return deviceCountMap;
   }
+
+  @Override
+  public void setPushDownLimit(long pushDownLimit) {
+    throw new IllegalStateException("Should never push down limit to 
AggregationTableScanNode.");
+  }
+
+  @Override
+  public void setPushDownOffset(long pushDownOffset) {
+    throw new IllegalStateException("Should never push down offset to 
AggregationTableScanNode.");
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushLimitOffsetIntoTableScan.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushLimitOffsetIntoTableScan.java
index 2993c8f3696..2bd9b778aec 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushLimitOffsetIntoTableScan.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/PushLimitOffsetIntoTableScan.java
@@ -50,7 +50,7 @@ import java.util.Set;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.PushPredicateIntoTableScan.containsDiffFunction;
 
 /**
- * <b>Optimization phase:</b> Distributed plan planning.
+ * <b>Optimization phase:</b> Logical plan planning.
  *
  * <p>The LIMIT OFFSET condition can be pushed down to the 
DeviceTableScanNode, when the following
  * conditions are met:

Reply via email to