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

Wei-hao-Li pushed a commit to branch fix-diff-order
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 410a52da81aefb1b2a662a6519413e083b3181d5
Author: Weihao Li <[email protected]>
AuthorDate: Fri May 8 16:45:39 2026 +0800

    fix
    
    Signed-off-by: Weihao Li <[email protected]>
---
 .../scalar/IoTDBDiffFunctionTableIT.java           | 24 ++++++++++++++++++++++
 .../relational/analyzer/StatementAnalyzer.java     | 11 +++++++++-
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/builtinfunction/scalar/IoTDBDiffFunctionTableIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/builtinfunction/scalar/IoTDBDiffFunctionTableIT.java
index 6bf1ef8db3e..36835792ff2 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/builtinfunction/scalar/IoTDBDiffFunctionTableIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/relational/it/query/old/builtinfunction/scalar/IoTDBDiffFunctionTableIT.java
@@ -146,4 +146,28 @@ public class IoTDBDiffFunctionTableIT {
         retArray,
         DATABASE_NAME);
   }
+
+  @Test
+  public void testDiffInSubQueryRespectsInnerOrderBy() {
+    String[] expectedHeader = new String[] {"time", "device_id", "s1", 
"s1_diff"};
+    String[] retArray =
+        new String[] {
+          "1970-02-27T20:53:20.001Z,d1,8,3.0,",
+          "1970-02-27T20:53:20.000Z,d1,null,null,",
+          "1970-01-01T00:00:00.006Z,d1,null,null,",
+          "1970-01-01T00:00:00.005Z,d1,5,1.0,",
+          "1970-01-01T00:00:00.004Z,d1,4,2.0,",
+          "1970-01-01T00:00:00.003Z,d1,null,null,",
+          "1970-01-01T00:00:00.002Z,d1,2,1.0,",
+          "1970-01-01T00:00:00.001Z,d1,1,null,"
+        };
+    tableResultSetEqualTest(
+        "SELECT * FROM ("
+            + "select time, device_id, s1, diff(s1) as s1_diff "
+            + "from table1 where device_id='d1' ORDER by time"
+            + ") ORDER by time DESC",
+        expectedHeader,
+        retArray,
+        DATABASE_NAME);
+  }
 }
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 6d3326dd402..ffc39edd6de 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
@@ -281,6 +281,7 @@ import static 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.Join.
 import static 
org.apache.iotdb.commons.queryengine.plan.relational.sql.ast.PatternRecognitionRelation.RowsPerMatch.ONE;
 import static 
org.apache.iotdb.commons.schema.table.TsTable.TABLE_ALLOWED_PROPERTIES;
 import static 
org.apache.iotdb.commons.udf.builtin.relational.TableBuiltinScalarFunction.DATE_BIN;
+import static 
org.apache.iotdb.commons.udf.builtin.relational.TableBuiltinScalarFunction.DIFF;
 import static 
org.apache.iotdb.db.queryengine.execution.warnings.StandardWarningCode.REDUNDANT_ORDER_BY;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.AggregationAnalyzer.verifyOrderByAggregations;
 import static 
org.apache.iotdb.db.queryengine.plan.relational.analyzer.AggregationAnalyzer.verifySourceAggregations;
@@ -1188,7 +1189,8 @@ public class StatementAnalyzer {
         if ((sourceScope.getOuterQueryParent().isPresent() || !isTopLevel)
             && !node.getLimit().isPresent()
             && !node.getOffset().isPresent()
-            && !hasFillInParentScope) {
+            && !hasFillInParentScope
+            && !containsDiffFunction(outputExpressions)) {
           // not the root scope and ORDER BY is ineffective
           analysis.markRedundantOrderBy(orderBy);
           warningCollector.add(
@@ -1301,6 +1303,13 @@ public class StatementAnalyzer {
       return windowFunctions;
     }
 
+    private boolean containsDiffFunction(List<Expression> expressions) {
+      return ExpressionTreeUtils.extractExpressions(expressions, 
FunctionCall.class).stream()
+          .anyMatch(
+              functionCall ->
+                  
functionCall.getName().getSuffix().equalsIgnoreCase(DIFF.getFunctionName()));
+    }
+
     private void resolveFunctionCallAndMeasureWindows(QuerySpecification 
querySpecification) {
       ImmutableList.Builder<Expression> expressions = ImmutableList.builder();
 

Reply via email to