This is an automated email from the ASF dual-hosted git repository. JackieTien97 pushed a commit to branch codex/backport-pr-18179-dev-1.3 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit cc6183b28445448dd0ba9a5cc9214c2816caea27 Author: JackieTien97 <[email protected]> AuthorDate: Sat Jul 11 14:07:48 2026 +0800 Fix query retry CI regressions --- .../db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java | 9 +++++++-- .../iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java | 9 +++++++-- .../db/queryengine/plan/analyze/TemplatedAnalyzeRetryTest.java | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java index b7ac5792079..43c810ac808 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java @@ -181,12 +181,17 @@ public class TemplatedAggregationAnalyze { FunctionExpression countTimeExpression = (FunctionExpression) selectExpression; // The parsed count_time(*) expression belongs to the statement and may be analyzed again // after a dispatch failure. Build a template-only expression instead of replacing its - // wildcard child in place. + // wildcard child in place. Prime the copy's expression string before replacing the child: + // the result header must remain count_time(*), while the planning output symbol must be + // count_time(Time), just as it was when the parsed expression was mutated in place. FunctionExpression templatedCountTimeExpression = new FunctionExpression( countTimeExpression.getFunctionName(), new LinkedHashMap<>(countTimeExpression.getFunctionAttributes()), - Collections.singletonList(new TimestampOperand())); + new ArrayList<>(countTimeExpression.getExpressions())); + templatedCountTimeExpression.getExpressionString(); + templatedCountTimeExpression.setExpressions( + Collections.singletonList(new TimestampOperand())); templatedCountTimeExpression.setFunctionType(countTimeExpression.getFunctionType()); outputExpressions.add(new Pair<>(templatedCountTimeExpression, resultColumn.getAlias())); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java index 32d663c84e2..d348f2ba3d1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java @@ -488,7 +488,8 @@ public class LogicalPlanBuilder { // DEVICE and TIME are implicit merge keys for DeviceView. Append them to a planning-owned copy // so rebuilding the plan after a dispatch failure does not mutate the parsed statement or - // accumulate duplicate keys. + // accumulate duplicate keys. Keep the complete parameter in Analysis because a downstream + // SortNode must use the same implicit keys without reading a mutated QueryStatement. List<SortItem> sortItemList = new ArrayList<>(queryStatement.getSortItemList()); if (!queryStatement.isOrderByDevice()) { sortItemList.add(new SortItem(OrderByKey.DEVICE, Ordering.ASC)); @@ -498,6 +499,7 @@ public class LogicalPlanBuilder { } OrderByParameter orderByParameter = new OrderByParameter(sortItemList); + analysis.setMergeOrderParameter(orderByParameter); long limitValue = queryStatement.hasOffset() @@ -1344,7 +1346,10 @@ public class LogicalPlanBuilder { Set<Expression> orderByExpressions = analysis.getOrderByExpressions(); updateTypeProvider(orderByExpressions); - OrderByParameter orderByParameter = new OrderByParameter(queryStatement.getSortItemList()); + OrderByParameter orderByParameter = + queryStatement.isAlignByDevice() + ? analysis.getMergeOrderParameter() + : new OrderByParameter(queryStatement.getSortItemList()); if (orderByParameter.isEmpty()) { return this; } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAnalyzeRetryTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAnalyzeRetryTest.java index 9a45ac82fb1..773da476242 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAnalyzeRetryTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAnalyzeRetryTest.java @@ -70,6 +70,7 @@ public class TemplatedAnalyzeRetryTest { FunctionExpression analyzedCountTimeExpression = (FunctionExpression) analysis.getAggregationExpressions().iterator().next(); assertNotSame(countTimeExpression, analyzedCountTimeExpression); + assertEquals("count_time(*)", analyzedCountTimeExpression.getExpressionString()); assertEquals("count_time(Time)", analyzedCountTimeExpression.getOutputSymbol()); // QueryExecution analyzes the same statement again when retrying a dispatch failure.
