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

caogaofei pushed a commit to branch beyyes/fix_node_ordering
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 50dda9837afe5f1beebfcd27a05b27ae1c908e7d
Author: Beyyes <[email protected]>
AuthorDate: Wed Apr 2 14:09:20 2025 +0800

    Reapply "Fix optimizers doesn't work when execute Explain Analyze query"
    
    This reverts commit a2f49dce98e6890fa7754e669700d848735f5816.
---
 .../plan/planner/plan/node/PlanGraphPrinter.java   |  9 ++++
 .../relational/planner/TableLogicalPlanner.java    | 13 +++++-
 .../iterative/rule/PruneExplainAnalyzeColumns.java | 49 ++++++++++++++++++++++
 .../planner/node/ExplainAnalyzeNode.java           | 20 +++++++--
 .../plan/relational/planner/node/Patterns.java     |  4 ++
 .../optimizations/LogicalOptimizeFactory.java      |  2 +
 .../optimizations/UnaliasSymbolReferences.java     | 15 ++++++-
 .../relational/analyzer/ExplainAnalyzeTest.java    | 43 +++++++++++++++++++
 .../plan/relational/planner/PlanTester.java        |  8 ++--
 .../planner/assertions/PlanMatchPattern.java       | 13 ++++++
 10 files changed, 165 insertions(+), 11 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
index f6d90ce4a6b..d9eef926e92 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanGraphPrinter.java
@@ -71,6 +71,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.AssignUnique
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.DeviceTableScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.EnforceSingleRowNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExchangeNode;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExplainAnalyzeNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.GapFillNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.GroupNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.LinearFillNode;
@@ -822,6 +823,14 @@ public class PlanGraphPrinter extends 
PlanVisitor<List<String>, PlanGraphPrinter
     return render(node, boxValue, context);
   }
 
+  @Override
+  public List<String> visitExplainAnalyze(ExplainAnalyzeNode node, 
GraphContext context) {
+    List<String> boxValue = new ArrayList<>();
+    boxValue.add(String.format("ExplainAnalyze-%s", 
node.getPlanNodeId().getId()));
+    boxValue.add(String.format("ChildPermittedOutputs: %s", 
node.getChildPermittedOutputs()));
+    return render(node, boxValue, context);
+  }
+
   @Override
   public List<String> visitGapFill(GapFillNode node, GraphContext context) {
     List<String> boxValue = new ArrayList<>();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java
index c9bfb879181..6f92192c092 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/TableLogicalPlanner.java
@@ -480,6 +480,16 @@ public class TableLogicalPlanner {
         createRelationPlan(analysis, (Query) (statement.getStatement()));
     Symbol symbol =
         symbolAllocator.newSymbol(ColumnHeaderConstant.EXPLAIN_ANALYZE, 
StringType.getInstance());
+
+    // recording permittedOutputs of ExplainAnalyzeNode's child
+    RelationType outputDescriptor = 
analysis.getOutputDescriptor(statement.getStatement());
+    ImmutableList.Builder<Symbol> childPermittedOutputs = 
ImmutableList.builder();
+    for (Field field : outputDescriptor.getVisibleFields()) {
+      int fieldIndex = outputDescriptor.indexOf(field);
+      Symbol columnSymbol = originalQueryPlan.getSymbol(fieldIndex);
+      childPermittedOutputs.add(columnSymbol);
+    }
+
     PlanNode newRoot =
         new ExplainAnalyzeNode(
             queryContext.getQueryId().genPlanNodeId(),
@@ -487,7 +497,8 @@ public class TableLogicalPlanner {
             statement.isVerbose(),
             queryContext.getLocalQueryId(),
             queryContext.getTimeOut(),
-            symbol);
+            symbol,
+            childPermittedOutputs.build());
     return new RelationPlan(
         newRoot,
         originalQueryPlan.getScope(),
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneExplainAnalyzeColumns.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneExplainAnalyzeColumns.java
new file mode 100644
index 00000000000..697c1a55a8d
--- /dev/null
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/iterative/rule/PruneExplainAnalyzeColumns.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+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.ExplainAnalyzeNode;
+import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Captures;
+import org.apache.iotdb.db.queryengine.plan.relational.utils.matching.Pattern;
+
+import com.google.common.collect.ImmutableSet;
+
+import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.Util.restrictChildOutputs;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.Patterns.explainAnalyze;
+
+public class PruneExplainAnalyzeColumns implements Rule<ExplainAnalyzeNode> {
+  private static final Pattern<ExplainAnalyzeNode> PATTERN = explainAnalyze();
+
+  @Override
+  public Pattern<ExplainAnalyzeNode> getPattern() {
+    return PATTERN;
+  }
+
+  @Override
+  public Result apply(ExplainAnalyzeNode analyzeNode, Captures captures, 
Context context) {
+    return restrictChildOutputs(
+            context.getIdAllocator(),
+            analyzeNode,
+            ImmutableSet.copyOf(analyzeNode.getChildPermittedOutputs()))
+        .map(Result::ofPlanNode)
+        .orElse(Result.empty());
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ExplainAnalyzeNode.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ExplainAnalyzeNode.java
index 7332743050c..23aa8baad2d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ExplainAnalyzeNode.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ExplainAnalyzeNode.java
@@ -37,6 +37,7 @@ public class ExplainAnalyzeNode extends 
SingleChildProcessNode {
   private final long queryId;
   private final long timeout;
   private final Symbol outputSymbol;
+  private final List<Symbol> childPermittedOutputs;
 
   public ExplainAnalyzeNode(
       PlanNodeId id,
@@ -44,17 +45,20 @@ public class ExplainAnalyzeNode extends 
SingleChildProcessNode {
       boolean verbose,
       long queryId,
       long timeout,
-      Symbol outputSymbol) {
+      Symbol outputSymbol,
+      List<Symbol> childPermittedOutputs) {
     super(id, child);
     this.verbose = verbose;
     this.timeout = timeout;
     this.queryId = queryId;
     this.outputSymbol = outputSymbol;
+    this.childPermittedOutputs = childPermittedOutputs;
   }
 
   @Override
   public PlanNode clone() {
-    return new ExplainAnalyzeNode(getPlanNodeId(), child, verbose, queryId, 
timeout, outputSymbol);
+    return new ExplainAnalyzeNode(
+        getPlanNodeId(), child, verbose, queryId, timeout, outputSymbol, 
childPermittedOutputs);
   }
 
   @Override
@@ -72,10 +76,20 @@ public class ExplainAnalyzeNode extends 
SingleChildProcessNode {
     return Collections.singletonList(outputSymbol);
   }
 
+  public List<Symbol> getChildPermittedOutputs() {
+    return childPermittedOutputs;
+  }
+
   @Override
   public PlanNode replaceChildren(List<PlanNode> newChildren) {
     return new 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExplainAnalyzeNode(
-        getPlanNodeId(), newChildren.get(0), verbose, queryId, timeout, 
outputSymbol);
+        getPlanNodeId(),
+        newChildren.get(0),
+        verbose,
+        queryId,
+        timeout,
+        outputSymbol,
+        childPermittedOutputs);
   }
 
   // ExplainAnalyze should be at the same region as Coordinator all the time. 
Therefore, there will
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java
index 83391f24d3f..1ebc30a72ed 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/Patterns.java
@@ -133,6 +133,10 @@ public final class Patterns {
     return typeOf(OutputNode.class);
   }
 
+  public static Pattern<ExplainAnalyzeNode> explainAnalyze() {
+    return typeOf(ExplainAnalyzeNode.class);
+  }
+
   public static Pattern<ProjectNode> project() {
     return typeOf(ProjectNode.class);
   }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java
index 57f7f93b19f..f3010fb3539 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/LogicalOptimizeFactory.java
@@ -43,6 +43,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.Pr
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneCorrelatedJoinCorrelation;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneDistinctAggregation;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneEnforceSingleRowColumns;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneExplainAnalyzeColumns;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneFillColumns;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneFilterColumns;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.iterative.rule.PruneGapFillColumns;
@@ -115,6 +116,7 @@ public class LogicalOptimizeFactory {
             new PruneMarkDistinctColumns(),
             new PruneOffsetColumns(),
             new PruneOutputSourceColumns(),
+            new PruneExplainAnalyzeColumns(),
             new PruneProjectColumns(),
             new PruneSortColumns(),
             new PruneTableFunctionProcessorColumns(),
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java
index 0a08d748742..d12db4d3034 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/UnaliasSymbolReferences.java
@@ -352,10 +352,21 @@ public class UnaliasSymbolReferences implements 
PlanOptimizer {
     @Override
     public PlanAndMappings visitExplainAnalyze(ExplainAnalyzeNode node, 
UnaliasContext context) {
       PlanAndMappings rewrittenSource = node.getChild().accept(this, context);
+      Map<Symbol, Symbol> mapping = new 
HashMap<>(rewrittenSource.getMappings());
+      SymbolMapper mapper = symbolMapper(mapping);
+
+      List<Symbol> newChildPermittedOutputs = 
mapper.map(node.getChildPermittedOutputs());
 
       return new PlanAndMappings(
-          node.replaceChildren(ImmutableList.of(rewrittenSource.getRoot())),
-          rewrittenSource.getMappings());
+          new ExplainAnalyzeNode(
+              node.getPlanNodeId(),
+              rewrittenSource.getRoot(),
+              node.isVerbose(),
+              node.getQueryId(),
+              node.getTimeout(),
+              node.getOutputSymbols().get(0),
+              newChildPermittedOutputs),
+          mapping);
     }
 
     @Override
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/ExplainAnalyzeTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/ExplainAnalyzeTest.java
new file mode 100644
index 00000000000..f20ebab3e98
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/ExplainAnalyzeTest.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
+
+import org.apache.iotdb.db.queryengine.plan.planner.plan.LogicalQueryPlan;
+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.aggregationTableScan;
+import static 
org.apache.iotdb.db.queryengine.plan.relational.planner.assertions.PlanMatchPattern.explainAnalyze;
+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;
+
+public class ExplainAnalyzeTest {
+  private final PlanTester planTester = new PlanTester();
+
+  @Test
+  public void testColumnPrune() {
+    LogicalQueryPlan logicalQueryPlan =
+        planTester.createPlan("explain analyze select count(s1) from table1 
group by tag1");
+    assertPlan(
+        logicalQueryPlan, 
output(explainAnalyze(project(aggregation(aggregationTableScan())))));
+  }
+}
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
index 9a98ab96c7b..8eb019db607 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanTester.java
@@ -115,7 +115,7 @@ public class PlanTester {
     distributedQueryPlan = null;
     MPPQueryContext context = new MPPQueryContext(sql, queryId, sessionInfo, 
null, null);
 
-    Analysis analysis = analyze(sql, metadata);
+    Analysis analysis = analyze(sql, metadata, context);
     this.analysis = analysis;
     this.symbolAllocator = new SymbolAllocator();
 
@@ -137,7 +137,7 @@ public class PlanTester {
     distributedQueryPlan = null;
     MPPQueryContext context = new MPPQueryContext(sql, queryId, sessionInfo, 
null, null);
 
-    Analysis analysis = analyze(sql, metadata);
+    Analysis analysis = analyze(sql, metadata, context);
 
     TableLogicalPlanner logicalPlanner =
         new TableLogicalPlanner(
@@ -146,7 +146,7 @@ public class PlanTester {
     return logicalPlanner.plan(analysis);
   }
 
-  public static Analysis analyze(String sql, Metadata metadata) {
+  public static Analysis analyze(String sql, Metadata metadata, 
MPPQueryContext context) {
     SqlParser sqlParser = new SqlParser();
     String databaseName;
     if (metadata instanceof TSBSMetadata) {
@@ -160,8 +160,6 @@ public class PlanTester {
     SessionInfo session =
         new SessionInfo(
             0, "test", ZoneId.systemDefault(), databaseName, 
IClientSession.SqlDialect.TABLE);
-    final MPPQueryContext context =
-        new MPPQueryContext(sql, new QueryId("test_query"), session, null, 
null);
     return analyzeStatement(
         statement, metadata, context, sqlParser, session, new 
AllowAllAccessControl());
   }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
index 5fc2d03e53e..b09530d898c 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/planner/assertions/PlanMatchPattern.java
@@ -34,6 +34,7 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.CollectNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.DeviceTableScanNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.EnforceSingleRowNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExchangeNode;
+import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.ExplainAnalyzeNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode;
 import org.apache.iotdb.db.queryengine.plan.relational.planner.node.GroupNode;
 import 
org.apache.iotdb.db.queryengine.plan.relational.planner.node.InformationSchemaTableScanNode;
@@ -251,6 +252,10 @@ public final class PlanMatchPattern {
     return this;
   }
 
+  public static PlanMatchPattern aggregation(PlanMatchPattern source) {
+    return node(AggregationNode.class, source);
+  }
+
   public static PlanMatchPattern aggregation(
       Map<String, ExpectedValueProvider<AggregationFunction>> aggregations,
       PlanMatchPattern source) {
@@ -416,6 +421,10 @@ public final class PlanMatchPattern {
     return result;
   }
 
+  public static PlanMatchPattern aggregationTableScan() {
+    return node(AggregationTableScanNode.class);
+  }
+
   public static PlanMatchPattern markDistinct(
       String markerSymbol, List<String> distinctSymbols, PlanMatchPattern 
source) {
     return node(MarkDistinctNode.class, source)
@@ -571,6 +580,10 @@ public final class PlanMatchPattern {
     return output(outputs, source).withExactOutputs(outputs);
   }
 
+  public static PlanMatchPattern explainAnalyze(PlanMatchPattern source) {
+    return node(ExplainAnalyzeNode.class, source);
+  }
+
   public static PlanMatchPattern project(PlanMatchPattern source) {
     return node(ProjectNode.class, source);
   }

Reply via email to