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]