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 7b18b01865e21a..a8376464f11fa4 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 void computeUniform(DataTrait.Builder builder) { } 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 void computeUniform(DataTrait.Builder builder) { 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 c2fa770890f659..fd23de7a2f46d6 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.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 @@ void testBroadcastJoin() { PhysicalHashJoin 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 @@ void testComputeProjectOutputProperties() { 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 leftOutput = Lists.newArrayList(leftSlot); + List 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 idGenerator = GroupId.createGenerator(); + GroupPlan leftGroupPlan = new GroupPlan(new Group(idGenerator.getNextId(), leftLogical)); + GroupPlan rightGroupPlan = new GroupPlan(new Group(idGenerator.getNextId(), rightLogical)); + + PhysicalHashJoin 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 leftOutput = Lists.newArrayList(leftSlot); + List 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 idGenerator = GroupId.createGenerator(); + GroupPlan leftGroupPlan = new GroupPlan(new Group(idGenerator.getNextId(), leftLogical)); + GroupPlan rightGroupPlan = new GroupPlan(new Group(idGenerator.getNextId(), rightLogical)); + + PhysicalHashJoin 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 leftOutput = Lists.newArrayList(leftSlot); + List 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 idGenerator = GroupId.createGenerator(); + GroupPlan leftGroupPlan = new GroupPlan(new Group(idGenerator.getNextId(), leftLogical)); + GroupPlan rightGroupPlan = new GroupPlan(new Group(idGenerator.getNextId(), rightLogical)); + + PhysicalHashJoin 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 leftOutput = Lists.newArrayList(leftSlot); + List 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 idGenerator = GroupId.createGenerator(); + GroupPlan leftGroupPlan = new GroupPlan(new Group(idGenerator.getNextId(), leftLogical)); + GroupPlan rightGroupPlan = new GroupPlan(new Group(idGenerator.getNextId(), rightLogical)); + + PhysicalHashJoin 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)); + } }