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 5b3b20c2f8b [fix](asof_join)PhysicalHashJoin's computeUniform method 
should process asof join properly (#62730)
5b3b20c2f8b is described below

commit 5b3b20c2f8bcea8cc03d0a3472336e112a90dd31
Author: starocean999 <[email protected]>
AuthorDate: Tue Jun 2 17:48:27 2026 +0800

    [fix](asof_join)PhysicalHashJoin's computeUniform method should process 
asof join properly (#62730)
    
    ### What problem does this PR solve?
    Extend PhysicalHashJoin to correctly handle ASOF join variants so trait
    propagation, equal-set extraction, and functional dependency (FD)
    calculations work for ASOF join
---
 .../trees/plans/physical/PhysicalHashJoin.java     |   4 +
 .../properties/ChildOutputPropertyDeriverTest.java | 167 ++++++++++++++++++++-
 2 files changed, 170 insertions(+), 1 deletion(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
index 7b18b01865e..a8376464f11 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHashJoin.java
@@ -305,6 +305,8 @@ public class PhysicalHashJoin<
         }
         switch (joinType) {
             case INNER_JOIN:
+            case ASOF_LEFT_INNER_JOIN:
+            case ASOF_RIGHT_INNER_JOIN:
             case CROSS_JOIN:
                 
builder.addUniformSlot(left().getLogicalProperties().getTrait());
                 
builder.addUniformSlot(right().getLogicalProperties().getTrait());
@@ -319,10 +321,12 @@ public class PhysicalHashJoin<
                 
builder.addUniformSlot(right().getLogicalProperties().getTrait());
                 break;
             case LEFT_OUTER_JOIN:
+            case ASOF_LEFT_OUTER_JOIN:
                 
builder.addUniformSlot(left().getLogicalProperties().getTrait());
                 
builder.addUniformSlotForOuterJoinNullableSide(right().getLogicalProperties().getTrait());
                 break;
             case RIGHT_OUTER_JOIN:
+            case ASOF_RIGHT_OUTER_JOIN:
                 
builder.addUniformSlot(right().getLogicalProperties().getTrait());
                 
builder.addUniformSlotForOuterJoinNullableSide(left().getLogicalProperties().getTrait());
                 break;
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriverTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriverTest.java
index c2fa770890f..fd23de7a2f4 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriverTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/properties/ChildOutputPropertyDeriverTest.java
@@ -45,6 +45,7 @@ import org.apache.doris.nereids.trees.plans.LimitPhase;
 import org.apache.doris.nereids.trees.plans.RelationId;
 import org.apache.doris.nereids.trees.plans.SortPhase;
 import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation;
+import org.apache.doris.nereids.trees.plans.physical.AbstractPhysicalPlan;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalAssertNumRows;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashAggregate;
 import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
@@ -590,7 +591,7 @@ class ChildOutputPropertyDeriverTest {
         PhysicalHashJoin<GroupPlan, GroupPlan> join = new 
PhysicalHashJoin<>(JoinType.INNER_JOIN,
                 Lists.newArrayList(new EqualTo(
                         leftSlot, rightSlot
-                        )),
+                )),
                 ExpressionUtils.EMPTY_CONDITION, new 
DistributeHint(DistributeType.NONE),
                 Optional.empty(), logicalProperties, leftGroupPlan, 
rightGroupPlan);
         GroupExpression groupExpression = new GroupExpression(join);
@@ -971,4 +972,168 @@ class ChildOutputPropertyDeriverTest {
         PhysicalProperties phyProp3 = 
ChildOutputPropertyDeriver.computeProjectOutputProperties(projects3, hashC1);
         Assertions.assertEquals(hashC1, phyProp3);
     }
+
+    @Test
+    void testComputeUniformAfterRecomputeLogicalProperties() {
+        // left child has a uniform slot, right child empty
+        SlotReference leftSlot = new SlotReference(new ExprId(100), "left", 
IntegerType.INSTANCE, false,
+                Collections.emptyList());
+        SlotReference rightSlot = new SlotReference(new ExprId(101), "right", 
IntegerType.INSTANCE, false,
+                Collections.emptyList());
+        List<Slot> leftOutput = Lists.newArrayList(leftSlot);
+        List<Slot> rightOutput = Lists.newArrayList(rightSlot);
+
+        DataTrait.Builder leftBuilder = new DataTrait.Builder();
+        leftBuilder.addUniformSlot(leftSlot);
+        DataTrait leftTrait = leftBuilder.build();
+
+        LogicalProperties leftLogical = new LogicalProperties(() -> 
leftOutput, () -> leftTrait);
+        LogicalProperties rightLogical = new LogicalProperties(() -> 
rightOutput, () -> DataTrait.EMPTY_TRAIT);
+
+        IdGenerator<GroupId> idGenerator = GroupId.createGenerator();
+        GroupPlan leftGroupPlan = new GroupPlan(new 
Group(idGenerator.getNextId(), leftLogical));
+        GroupPlan rightGroupPlan = new GroupPlan(new 
Group(idGenerator.getNextId(), rightLogical));
+
+        PhysicalHashJoin<GroupPlan, GroupPlan> join = new 
PhysicalHashJoin<>(JoinType.ASOF_LEFT_OUTER_JOIN,
+                ExpressionUtils.EMPTY_CONDITION, 
ExpressionUtils.EMPTY_CONDITION,
+                new DistributeHint(DistributeType.NONE), Optional.empty(), 
logicalProperties,
+                leftGroupPlan, rightGroupPlan);
+
+        // simulate physical-tree logical prop recompute by resetting logical 
properties on the join
+        AbstractPhysicalPlan processed = (AbstractPhysicalPlan) 
join.resetLogicalProperties();
+        processed = (AbstractPhysicalPlan) 
processed.copyStatsAndGroupIdFrom((AbstractPhysicalPlan) join);
+
+        Assertions.assertInstanceOf(PhysicalHashJoin.class, processed);
+
+        DataTrait.Builder builder = new DataTrait.Builder();
+        processed.computeUniform(builder);
+        DataTrait result = builder.build();
+
+        // left slot should still be recognized as uniform after recompute
+        Assertions.assertTrue(result.isUniformAndNotNull(leftSlot));
+    }
+
+    @Test
+    void testComputeUniformAfterRecomputeLogicalProperties_AsOfLeftInner() {
+        SlotReference leftSlot = new SlotReference(new ExprId(200), "l", 
IntegerType.INSTANCE, false,
+                Collections.emptyList());
+        SlotReference rightSlot = new SlotReference(new ExprId(201), "r", 
IntegerType.INSTANCE, false,
+                Collections.emptyList());
+        List<Slot> leftOutput = Lists.newArrayList(leftSlot);
+        List<Slot> rightOutput = Lists.newArrayList(rightSlot);
+
+        DataTrait.Builder leftBuilder = new DataTrait.Builder();
+        leftBuilder.addUniformSlot(leftSlot);
+        DataTrait leftTrait = leftBuilder.build();
+
+        DataTrait.Builder rightBuilder = new DataTrait.Builder();
+        rightBuilder.addUniformSlot(rightSlot);
+        DataTrait rightTrait = rightBuilder.build();
+
+        LogicalProperties leftLogical = new LogicalProperties(() -> 
leftOutput, () -> leftTrait);
+        LogicalProperties rightLogical = new LogicalProperties(() -> 
rightOutput, () -> rightTrait);
+
+        IdGenerator<GroupId> idGenerator = GroupId.createGenerator();
+        GroupPlan leftGroupPlan = new GroupPlan(new 
Group(idGenerator.getNextId(), leftLogical));
+        GroupPlan rightGroupPlan = new GroupPlan(new 
Group(idGenerator.getNextId(), rightLogical));
+
+        PhysicalHashJoin<GroupPlan, GroupPlan> join = new 
PhysicalHashJoin<>(JoinType.ASOF_LEFT_INNER_JOIN,
+                ExpressionUtils.EMPTY_CONDITION, 
ExpressionUtils.EMPTY_CONDITION,
+                new DistributeHint(DistributeType.NONE), Optional.empty(), 
logicalProperties,
+                leftGroupPlan, rightGroupPlan);
+
+        // simulate physical-tree logical prop recompute by resetting logical 
properties on the join
+        AbstractPhysicalPlan processed = (AbstractPhysicalPlan) 
join.resetLogicalProperties();
+        processed = (AbstractPhysicalPlan) 
processed.copyStatsAndGroupIdFrom((AbstractPhysicalPlan) join);
+
+        Assertions.assertInstanceOf(PhysicalHashJoin.class, processed);
+
+        DataTrait.Builder builder = new DataTrait.Builder();
+        processed.computeUniform(builder);
+        DataTrait result = builder.build();
+
+        Assertions.assertTrue(result.isUniformAndNotNull(leftSlot));
+        Assertions.assertTrue(result.isUniformAndNotNull(rightSlot));
+    }
+
+    @Test
+    void testComputeUniformAfterRecomputeLogicalProperties_AsOfRightInner() {
+        SlotReference leftSlot = new SlotReference(new ExprId(300), "l2", 
IntegerType.INSTANCE, false,
+                Collections.emptyList());
+        SlotReference rightSlot = new SlotReference(new ExprId(301), "r2", 
IntegerType.INSTANCE, false,
+                Collections.emptyList());
+        List<Slot> leftOutput = Lists.newArrayList(leftSlot);
+        List<Slot> rightOutput = Lists.newArrayList(rightSlot);
+
+        DataTrait.Builder leftBuilder = new DataTrait.Builder();
+        leftBuilder.addUniformSlot(leftSlot);
+        DataTrait leftTrait = leftBuilder.build();
+
+        DataTrait.Builder rightBuilder = new DataTrait.Builder();
+        rightBuilder.addUniformSlot(rightSlot);
+        DataTrait rightTrait = rightBuilder.build();
+
+        LogicalProperties leftLogical = new LogicalProperties(() -> 
leftOutput, () -> leftTrait);
+        LogicalProperties rightLogical = new LogicalProperties(() -> 
rightOutput, () -> rightTrait);
+
+        IdGenerator<GroupId> idGenerator = GroupId.createGenerator();
+        GroupPlan leftGroupPlan = new GroupPlan(new 
Group(idGenerator.getNextId(), leftLogical));
+        GroupPlan rightGroupPlan = new GroupPlan(new 
Group(idGenerator.getNextId(), rightLogical));
+
+        PhysicalHashJoin<GroupPlan, GroupPlan> join = new 
PhysicalHashJoin<>(JoinType.ASOF_RIGHT_INNER_JOIN,
+                ExpressionUtils.EMPTY_CONDITION, 
ExpressionUtils.EMPTY_CONDITION,
+                new DistributeHint(DistributeType.NONE), Optional.empty(), 
logicalProperties,
+                leftGroupPlan, rightGroupPlan);
+
+        // simulate physical-tree logical prop recompute by resetting logical 
properties on the join
+        AbstractPhysicalPlan processed = (AbstractPhysicalPlan) 
join.resetLogicalProperties();
+        processed = (AbstractPhysicalPlan) 
processed.copyStatsAndGroupIdFrom((AbstractPhysicalPlan) join);
+
+        Assertions.assertInstanceOf(PhysicalHashJoin.class, processed);
+
+        DataTrait.Builder builder = new DataTrait.Builder();
+        processed.computeUniform(builder);
+        DataTrait result = builder.build();
+
+        Assertions.assertTrue(result.isUniformAndNotNull(leftSlot));
+        Assertions.assertTrue(result.isUniformAndNotNull(rightSlot));
+    }
+
+    @Test
+    void testComputeUniformAfterRecomputeLogicalProperties_AsOfRightOuter() {
+        SlotReference leftSlot = new SlotReference(new ExprId(400), "l3", 
IntegerType.INSTANCE, false,
+                Collections.emptyList());
+        SlotReference rightSlot = new SlotReference(new ExprId(401), "r3", 
IntegerType.INSTANCE, false,
+                Collections.emptyList());
+        List<Slot> leftOutput = Lists.newArrayList(leftSlot);
+        List<Slot> rightOutput = Lists.newArrayList(rightSlot);
+
+        DataTrait.Builder rightBuilder = new DataTrait.Builder();
+        rightBuilder.addUniformSlot(rightSlot);
+        DataTrait rightTrait = rightBuilder.build();
+
+        LogicalProperties leftLogical = new LogicalProperties(() -> 
leftOutput, () -> DataTrait.EMPTY_TRAIT);
+        LogicalProperties rightLogical = new LogicalProperties(() -> 
rightOutput, () -> rightTrait);
+
+        IdGenerator<GroupId> idGenerator = GroupId.createGenerator();
+        GroupPlan leftGroupPlan = new GroupPlan(new 
Group(idGenerator.getNextId(), leftLogical));
+        GroupPlan rightGroupPlan = new GroupPlan(new 
Group(idGenerator.getNextId(), rightLogical));
+
+        PhysicalHashJoin<GroupPlan, GroupPlan> join = new 
PhysicalHashJoin<>(JoinType.ASOF_RIGHT_OUTER_JOIN,
+                ExpressionUtils.EMPTY_CONDITION, 
ExpressionUtils.EMPTY_CONDITION,
+                new DistributeHint(DistributeType.NONE), Optional.empty(), 
logicalProperties,
+                leftGroupPlan, rightGroupPlan);
+
+        // simulate physical-tree logical prop recompute by resetting logical 
properties on the join
+        AbstractPhysicalPlan processed = (AbstractPhysicalPlan) 
join.resetLogicalProperties();
+        processed = (AbstractPhysicalPlan) 
processed.copyStatsAndGroupIdFrom((AbstractPhysicalPlan) join);
+
+        Assertions.assertInstanceOf(PhysicalHashJoin.class, processed);
+
+        DataTrait.Builder builder = new DataTrait.Builder();
+        processed.computeUniform(builder);
+        DataTrait result = builder.build();
+
+        Assertions.assertTrue(result.isUniformAndNotNull(rightSlot));
+    }
 }


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

Reply via email to