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

starocean999 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new d4c31362ddd [fix](partition pruning) Preserve partition pruning state 
in plan copies (#67113)
d4c31362ddd is described below

commit d4c31362ddd906a22e85eef113677ccc89e18cbc
Author: feiniaofeiafei <[email protected]>
AuthorDate: Thu Aug 27 14:50:21 2026 +0800

    [fix](partition pruning) Preserve partition pruning state in plan copies 
(#67113)
    
    Issue Number: #62196
    
    Problem Summary: LogicalOlapScan.withRelationId reset partitionPruned
    and hasPartitionPredicate as a hidden side effect, which broke default
    deep-copy semantics. Preserve both fields while replacing the relation
    ID. Add an explicit DeepCopierContext option that StructInfo enables for
    MTMV union compensation, so copied OLAP scans invalidate only
    partitionPruned during the existing copy traversal and the following
    whole-tree rewrite reapplies partition pruning.
---
 .../nereids/rules/exploration/mv/StructInfo.java   |  6 ++++-
 .../nereids/trees/copier/DeepCopierContext.java    | 10 ++++++++
 .../trees/copier/LogicalPlanDeepCopier.java        |  4 +++
 .../trees/plans/logical/LogicalOlapScan.java       | 18 +++++++++++--
 .../plans/logical/LogicalOlapTableStreamScan.java  | 13 ++++++++++
 .../trees/copier/LogicalPlanDeepCopierTest.java    | 30 ++++++++++++++++++++++
 6 files changed, 78 insertions(+), 3 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java
index d4e0e3f5003..e5109b5516c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/StructInfo.java
@@ -975,8 +975,12 @@ public class StructInfo {
         }
         // Deep copy the plan to avoid the plan output is the same with the 
later union output, this may cause
         // exec by mistake
+        DeepCopierContext deepCopierContext = new DeepCopierContext();
+        // The compensation filter changes the partition range. Invalidate 
pruning during the copy to avoid
+        // another traversal before the following whole-tree rewrite applies 
partition pruning again.
+        deepCopierContext.setInvalidatePartitionPruning(true);
         queryPlanWithUnionFilter = new LogicalPlanDeepCopier().deepCopy(
-                (LogicalPlan) queryPlanWithUnionFilter, new 
DeepCopierContext());
+                (LogicalPlan) queryPlanWithUnionFilter, deepCopierContext);
         // rbo rewrite after adding filter on origin plan
         return 
Pair.of(MaterializedViewUtils.rewriteByRules(parentCascadesContext, context -> {
             Rewriter.getWholeTreeRewriter(context).execute();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/DeepCopierContext.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/DeepCopierContext.java
index c4772fb7e81..b898a08f7f1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/DeepCopierContext.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/DeepCopierContext.java
@@ -39,6 +39,16 @@ public class DeepCopierContext {
      * to ensure they keep same after deep copy
      */
     private final Map<RelationId, LogicalRelation> relationReplaceMap = 
Maps.newHashMap();
+    /** Whether copied OLAP scans should be marked for partition pruning 
again. */
+    private boolean invalidatePartitionPruning = false;
+
+    public void setInvalidatePartitionPruning(boolean 
invalidatePartitionPruning) {
+        this.invalidatePartitionPruning = invalidatePartitionPruning;
+    }
+
+    public boolean shouldInvalidatePartitionPruning() {
+        return invalidatePartitionPruning;
+    }
 
     public void putRelation(RelationId relationId, LogicalRelation 
newRelation) {
         relationReplaceMap.put(relationId, newRelation);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/LogicalPlanDeepCopier.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/LogicalPlanDeepCopier.java
index 29fd9e9e4c5..01472f1c920 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/LogicalPlanDeepCopier.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/copier/LogicalPlanDeepCopier.java
@@ -46,6 +46,7 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalHaving;
 import org.apache.doris.nereids.trees.plans.logical.LogicalIntersect;
 import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
 import org.apache.doris.nereids.trees.plans.logical.LogicalLimit;
+import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPartitionTopN;
 import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
@@ -107,6 +108,9 @@ public class LogicalPlanDeepCopier extends 
DefaultPlanRewriter<DeepCopierContext
         }
         LogicalCatalogRelation newRelation =
                 
catalogRelation.withRelationId(StatementScopeIdGenerator.newRelationId());
+        if (context.shouldInvalidatePartitionPruning() && newRelation 
instanceof LogicalOlapScan) {
+            newRelation = ((LogicalOlapScan) 
newRelation).withPartitionPruned(false);
+        }
         updateReplaceMapWithOutput(catalogRelation, newRelation, 
context.exprIdReplaceMap);
         List<NamedExpression> virtualColumns = 
catalogRelation.getVirtualColumns().stream()
                 .map(e -> {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
index 15d9a85b1e7..ddf73ac2ce2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java
@@ -657,11 +657,10 @@ public class LogicalOlapScan extends 
LogicalCatalogRelation implements OlapScan,
 
     @Override
     public LogicalOlapScan withRelationId(RelationId relationId) {
-        // we have to set partitionPruned to false, so that mtmv rewrite can 
prevent deadlock when rewriting union
         return AbstractPlan.copyWithSameId(this, () ->
                 new LogicalOlapScan(relationId, (Table) table, qualifier,
                 Optional.empty(), Optional.empty(),
-                selectedPartitionIds, false, false, selectedTabletIds,
+                selectedPartitionIds, partitionPruned, hasPartitionPredicate, 
selectedTabletIds,
                 selectedIndexId, indexSelected, preAggStatus, 
manuallySpecifiedPartitions,
                 hints, Maps.newHashMap(), Optional.empty(), tableSample, 
directMvScan,
                 colToSubPathsMap, selectedTabletIds, operativeSlots, 
virtualColumns, scoreOrderKeys,
@@ -764,6 +763,21 @@ public class LogicalOlapScan extends 
LogicalCatalogRelation implements OlapScan,
         return partitionPruned;
     }
 
+    /**
+     * Return a new scan with the specified partition pruning state.
+     */
+    public LogicalOlapScan withPartitionPruned(boolean partitionPruned) {
+        return AbstractPlan.copyWithSameId(this, () ->
+                new LogicalOlapScan(relationId, (Table) table, qualifier,
+                Optional.empty(), Optional.of(getLogicalProperties()),
+                selectedPartitionIds, partitionPruned, hasPartitionPredicate, 
selectedTabletIds,
+                selectedIndexId, indexSelected, preAggStatus, 
manuallySpecifiedPartitions,
+                hints, cacheSlotWithSlotName, cachedOutput, tableSample, 
directMvScan,
+                colToSubPathsMap, manuallySpecifiedTabletIds, operativeSlots, 
virtualColumns,
+                scoreOrderKeys, scoreLimit, scoreRangeInfo, annOrderKeys, 
annLimit, tableAlias,
+                partitionPrunablePredicates, scanParams));
+    }
+
     public List<Long> getSelectedTabletIds() {
         return selectedTabletIds;
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapTableStreamScan.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapTableStreamScan.java
index 48c40ce192a..62fcbfe5ac7 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapTableStreamScan.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapTableStreamScan.java
@@ -310,6 +310,19 @@ public class LogicalOlapTableStreamScan extends 
LogicalOlapScan {
                         partitionPrunablePredicates, scanParams, readMode));
     }
 
+    @Override
+    public LogicalOlapTableStreamScan withPartitionPruned(boolean 
partitionPruned) {
+        return AbstractPlan.copyWithSameId(this, () ->
+                new LogicalOlapTableStreamScan(relationId, (Table) table, 
qualifier,
+                        groupExpression, Optional.of(getLogicalProperties()),
+                        selectedPartitionIds, partitionPruned, 
hasPartitionPredicate, selectedTabletIds,
+                        selectedIndexId, indexSelected, preAggStatus, 
manuallySpecifiedPartitions,
+                        hints, cacheSlotWithSlotName, cachedOutput, 
tableSample, directMvScan,
+                        colToSubPathsMap, manuallySpecifiedTabletIds, 
operativeSlots, virtualColumns,
+                        scoreOrderKeys, scoreLimit, scoreRangeInfo, 
annOrderKeys, annLimit, tableAlias,
+                        partitionPrunablePredicates, scanParams, readMode));
+    }
+
     /**
      * Returns a new {@code LogicalOlapScan} carrying the supplied
      * {@link PartitionPrunablePredicate}. It is preserved across all other
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/copier/LogicalPlanDeepCopierTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/copier/LogicalPlanDeepCopierTest.java
index 98f07698a9e..b139d05910a 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/copier/LogicalPlanDeepCopierTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/copier/LogicalPlanDeepCopierTest.java
@@ -50,6 +50,36 @@ public class LogicalPlanDeepCopierTest {
         }
     }
 
+    @Test
+    public void testDeepCopyOlapScanPreservesPartitionPruningState() {
+        LogicalOlapScan relationPlan = PlanConstructor.newLogicalOlapScan(0, 
"a", 0);
+        relationPlan = 
relationPlan.withSelectedPartitionIds(relationPlan.getSelectedPartitionIds(), 
true);
+
+        LogicalOlapScan copiedPlan =
+                (LogicalOlapScan) 
relationPlan.accept(LogicalPlanDeepCopier.INSTANCE, new DeepCopierContext());
+
+        Assertions.assertTrue(relationPlan.isPartitionPruned());
+        Assertions.assertTrue(relationPlan.hasPartitionPredicate());
+        Assertions.assertTrue(copiedPlan.isPartitionPruned());
+        Assertions.assertTrue(copiedPlan.hasPartitionPredicate());
+    }
+
+    @Test
+    public void testDeepCopyOlapScanInvalidatesPartitionPruning() {
+        LogicalOlapScan relationPlan = PlanConstructor.newLogicalOlapScan(0, 
"a", 0);
+        relationPlan = 
relationPlan.withSelectedPartitionIds(relationPlan.getSelectedPartitionIds(), 
true);
+        DeepCopierContext context = new DeepCopierContext();
+        context.setInvalidatePartitionPruning(true);
+
+        LogicalOlapScan copiedPlan =
+                (LogicalOlapScan) 
relationPlan.accept(LogicalPlanDeepCopier.INSTANCE, context);
+
+        Assertions.assertTrue(relationPlan.isPartitionPruned());
+        Assertions.assertTrue(relationPlan.hasPartitionPredicate());
+        Assertions.assertFalse(copiedPlan.isPartitionPruned());
+        Assertions.assertTrue(copiedPlan.hasPartitionPredicate());
+    }
+
     @Test
     public void testDeepCopyOlapScanWithNonFirstOperativeSlot() {
         LogicalOlapScan relationPlan = PlanConstructor.newLogicalOlapScan(0, 
"a", 0);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to