You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by li...@apache.org on 2022/07/18 12:33:17 UTC

[doris] branch master updated: [feature](Nereids): hashCode(), equals() and UT. (#10870)

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

lingmiao 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 a849f5be71 [feature](Nereids): hashCode(), equals() and UT. (#10870)
a849f5be71 is described below

commit a849f5be7187f00321c8c25d6049bd187f3a50a8
Author: jakevin <ja...@gmail.com>
AuthorDate: Mon Jul 18 20:33:10 2022 +0800

    [feature](Nereids): hashCode(), equals() and UT. (#10870)
    
    Add hashCode(), equals() for operator.
    
    Add basic UT for them(need more detail test).
    
    **future ticket**: add hashCode(), equals() and UT for `Expression`
---
 .../java/org/apache/doris/nereids/memo/Memo.java   |   3 +-
 .../nereids/trees/plans/logical/LogicalFilter.java |  19 +-
 .../nereids/trees/plans/logical/LogicalJoin.java   |  25 ++-
 .../trees/plans/logical/LogicalOlapScan.java       |  17 ++
 .../trees/plans/logical/LogicalRelation.java       |  19 +-
 .../nereids/trees/plans/logical/LogicalSort.java   |  20 +-
 .../trees/plans/physical/PhysicalAggregate.java    |  24 +++
 .../trees/plans/physical/PhysicalFilter.java       |  17 ++
 .../trees/plans/physical/PhysicalHashJoin.java     |  17 ++
 .../trees/plans/physical/PhysicalHeapSort.java     |  28 ++-
 .../trees/plans/physical/PhysicalOlapScan.java     |  23 ++-
 .../trees/plans/physical/PhysicalProject.java      |  20 +-
 .../trees/plans/physical/PhysicalRelation.java     |  17 ++
 .../doris/nereids/trees/plans/EqualsTest.java      | 226 +++++++++++++++++++++
 14 files changed, 460 insertions(+), 15 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
index 78f4cb1d8f..5c8d6d914d 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
@@ -123,7 +123,8 @@ public class Memo {
     private GroupExpression insertOrRewriteGroupExpression(GroupExpression groupExpression, Group target,
             boolean rewrite, LogicalProperties logicalProperties) {
         GroupExpression existedGroupExpression = groupExpressions.get(groupExpression);
-        if (existedGroupExpression != null) {
+        if (existedGroupExpression != null
+                && existedGroupExpression.getParent().getLogicalProperties().equals(logicalProperties)) {
             if (target != null && !target.getGroupId().equals(existedGroupExpression.getParent().getGroupId())) {
                 mergeGroup(target, existedGroupExpression.getParent());
             }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
index c677227667..27d532d998 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
@@ -44,7 +44,7 @@ public class LogicalFilter<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_T
     }
 
     public LogicalFilter(Expression predicates, Optional<GroupExpression> groupExpression,
-                         Optional<LogicalProperties> logicalProperties, CHILD_TYPE child) {
+            Optional<LogicalProperties> logicalProperties, CHILD_TYPE child) {
         super(PlanType.LOGICAL_FILTER, groupExpression, logicalProperties, child);
         this.predicates = Objects.requireNonNull(predicates, "predicates can not be null");
     }
@@ -63,6 +63,23 @@ public class LogicalFilter<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_T
         return "LogicalFilter (" + predicates + ")";
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LogicalFilter that = (LogicalFilter) o;
+        return predicates.equals(that.predicates);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(predicates);
+    }
+
     @Override
     public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
         return visitor.visitLogicalFilter((LogicalFilter<Plan>) this, context);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
index 2391baaa99..05324fd75f 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
@@ -57,7 +57,7 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
     }
 
     public LogicalJoin(JoinType joinType, Optional<Expression> condition,
-                       LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
+            LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
         this(joinType, condition, Optional.empty(), Optional.empty(), leftChild, rightChild);
     }
 
@@ -68,8 +68,8 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
      * @param condition on clause for join node
      */
     public LogicalJoin(JoinType joinType, Optional<Expression> condition,
-                       Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties,
-                       LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
+            Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties,
+            LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
         super(PlanType.LOGICAL_JOIN, groupExpression, logicalProperties, leftChild, rightChild);
         this.joinType = Objects.requireNonNull(joinType, "joinType can not be null");
         this.condition = Objects.requireNonNull(condition, "condition can not be null");
@@ -129,6 +129,23 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
         return sb.append(")").toString();
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LogicalJoin that = (LogicalJoin) o;
+        return joinType == that.joinType && Objects.equals(condition, that.condition);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(joinType, condition);
+    }
+
     @Override
     public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
         return visitor.visitLogicalJoin((LogicalJoin<Plan, Plan>) this, context);
@@ -152,7 +169,7 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) {
         return new LogicalJoin<>(joinType, condition, groupExpression,
-            Optional.of(logicalProperties), left(), right());
+                Optional.of(logicalProperties), left(), right());
     }
 
     @Override
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 ed98dca195..1912c09c06 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
@@ -27,6 +27,7 @@ import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -54,6 +55,22 @@ public class LogicalOlapScan extends LogicalRelation  {
         return "ScanOlapTable([" + StringUtils.join(qualifier, ".") + "." + table.getName() + "])";
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass() || !super.equals(o)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode());
+    }
+
     @Override
     public Plan withGroupExpression(Optional<GroupExpression> groupExpression) {
         return new LogicalOlapScan(table, qualifier, groupExpression, Optional.of(logicalProperties));
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
index f551ff959e..499bd5e604 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
@@ -52,7 +52,7 @@ public abstract class LogicalRelation extends LogicalLeaf {
      * @param qualifier qualified relation name
      */
     public LogicalRelation(PlanType type, Table table, List<String> qualifier,
-                           Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties) {
+            Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties) {
         super(type, groupExpression, logicalProperties);
         this.table = Objects.requireNonNull(table, "table can not be null");
         this.qualifier = ImmutableList.copyOf(Objects.requireNonNull(qualifier, "qualifier can not be null"));
@@ -71,6 +71,23 @@ public abstract class LogicalRelation extends LogicalLeaf {
         return "LogicalRelation (" + StringUtils.join(qualifier, ".") + ")";
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LogicalRelation that = (LogicalRelation) o;
+        return Objects.equals(table.getId(), that.table.getId()) && Objects.equals(qualifier, that.qualifier);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(table.getId(), qualifier);
+    }
+
     @Override
     public List<Slot> computeOutput() {
         return table.getBaseSchema()
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSort.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSort.java
index e43c7bb3c5..a3cc5f2034 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSort.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSort.java
@@ -57,7 +57,7 @@ public class LogicalSort<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYP
      * Constructor for LogicalSort.
      */
     public LogicalSort(List<OrderKey> orderKeys, Optional<GroupExpression> groupExpression,
-                       Optional<LogicalProperties> logicalProperties, CHILD_TYPE child) {
+            Optional<LogicalProperties> logicalProperties, CHILD_TYPE child) {
         super(PlanType.LOGICAL_SORT, groupExpression, logicalProperties, child);
         this.orderKeys = Objects.requireNonNull(orderKeys, "orderKeys can not be null");
     }
@@ -84,6 +84,24 @@ public class LogicalSort<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYP
         return "Sort (" + StringUtils.join(orderKeys, ", ") + ")";
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        LogicalSort that = (LogicalSort) o;
+        return offset == that.offset && Objects.equals(orderKeys, that.orderKeys);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(orderKeys, offset);
+    }
+
+
     @Override
     public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
         return visitor.visitLogicalSort((LogicalSort<Plan>) this, context);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAggregate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAggregate.java
index 28563a1283..4d72f13bfb 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAggregate.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalAggregate.java
@@ -30,6 +30,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -113,6 +114,29 @@ public class PhysicalAggregate<CHILD_TYPE extends Plan> extends PhysicalUnary<CH
                 + "], [output=" + outputExpressionList + "])";
     }
 
+    /**
+     * Determine the equality with another operator
+     */
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PhysicalAggregate that = (PhysicalAggregate) o;
+        return Objects.equals(groupByExprList, that.groupByExprList)
+                && Objects.equals(outputExpressionList, that.outputExpressionList)
+                && Objects.equals(partitionExprList, that.partitionExprList)
+                && usingStream == that.usingStream
+                && aggPhase == that.aggPhase;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(groupByExprList, outputExpressionList, partitionExprList, aggPhase, usingStream);
+    }
+
     @Override
     public PhysicalUnary<Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 1);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
index 65acb24e60..46b7150a15 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
@@ -57,6 +57,23 @@ public class PhysicalFilter<CHILD_TYPE extends Plan> extends PhysicalUnary<CHILD
         return "Filter (" + predicates + ")";
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PhysicalFilter that = (PhysicalFilter) o;
+        return predicates.equals(that.predicates);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(predicates);
+    }
+
     @Override
     public List<Expression> getExpressions() {
         return ImmutableList.of(predicates);
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 144f7cd70f..a04e0baf83 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
@@ -93,6 +93,23 @@ public class PhysicalHashJoin<
         return sb.toString();
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PhysicalHashJoin that = (PhysicalHashJoin) o;
+        return joinType == that.joinType && Objects.equals(condition, that.condition);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(joinType, condition);
+    }
+
     @Override
     public PhysicalBinary<Plan, Plan> withChildren(List<Plan> children) {
         Preconditions.checkArgument(children.size() == 2);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHeapSort.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHeapSort.java
index e695ce2b4c..035ac93933 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHeapSort.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalHeapSort.java
@@ -29,6 +29,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -43,7 +44,7 @@ public class PhysicalHeapSort<CHILD_TYPE extends Plan> extends PhysicalUnary<CHI
 
 
     public PhysicalHeapSort(List<OrderKey> orderKeys, long limit, int offset,
-                            LogicalProperties logicalProperties, CHILD_TYPE child) {
+            LogicalProperties logicalProperties, CHILD_TYPE child) {
         this(orderKeys, limit, offset, Optional.empty(), logicalProperties, child);
     }
 
@@ -51,8 +52,8 @@ public class PhysicalHeapSort<CHILD_TYPE extends Plan> extends PhysicalUnary<CHI
      * Constructor of PhysicalHashJoinNode.
      */
     public PhysicalHeapSort(List<OrderKey> orderKeys, long limit, int offset,
-                            Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties,
-                            CHILD_TYPE child) {
+            Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties,
+            CHILD_TYPE child) {
         super(PlanType.PHYSICAL_SORT, groupExpression, logicalProperties, child);
         this.offset = offset;
         this.limit = limit;
@@ -71,6 +72,23 @@ public class PhysicalHeapSort<CHILD_TYPE extends Plan> extends PhysicalUnary<CHI
         return limit > -1;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PhysicalHeapSort that = (PhysicalHeapSort) o;
+        return offset == that.offset && limit == that.limit && Objects.equals(orderKeys, that.orderKeys);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(orderKeys, offset, limit);
+    }
+
     @Override
     public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
         return visitor.visitPhysicalHeapSort((PhysicalHeapSort<Plan>) this, context);
@@ -79,8 +97,8 @@ public class PhysicalHeapSort<CHILD_TYPE extends Plan> extends PhysicalUnary<CHI
     @Override
     public List<Expression> getExpressions() {
         return orderKeys.stream()
-            .map(OrderKey::getExpr)
-            .collect(ImmutableList.toImmutableList());
+                .map(OrderKey::getExpr)
+                .collect(ImmutableList.toImmutableList());
     }
 
     @Override
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
index 93bf57d90b..03596e7d37 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
@@ -29,6 +29,7 @@ import com.google.common.collect.Lists;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -48,7 +49,7 @@ public class PhysicalOlapScan extends PhysicalRelation {
      * @param qualifier table's name
      */
     public PhysicalOlapScan(OlapTable olapTable, List<String> qualifier,
-                            Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties) {
+            Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties) {
         super(PlanType.PHYSICAL_OLAP_SCAN, qualifier, groupExpression, logicalProperties);
         this.olapTable = olapTable;
         this.selectedIndexId = olapTable.getBaseIndexId();
@@ -81,6 +82,26 @@ public class PhysicalOlapScan extends PhysicalRelation {
                 + "], [index id=" + selectedIndexId + "])";
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass() || !super.equals(o)) {
+            return false;
+        }
+        PhysicalOlapScan that = (PhysicalOlapScan) o;
+        return selectedIndexId == that.selectedIndexId
+                && Objects.equals(selectedTabletId, that.selectedTabletId)
+                && Objects.equals(selectedPartitionId, that.selectedPartitionId)
+                && Objects.equals(olapTable, that.olapTable);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(selectedIndexId, selectedPartitionId, selectedTabletId, olapTable);
+    }
+
     @Override
     public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
         return visitor.visitPhysicalOlapScan(this, context);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
index 09671b1239..b99be40bed 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
@@ -44,7 +44,7 @@ public class PhysicalProject<CHILD_TYPE extends Plan> extends PhysicalUnary<CHIL
     }
 
     public PhysicalProject(List<NamedExpression> projects, Optional<GroupExpression> groupExpression,
-                           LogicalProperties logicalProperties, CHILD_TYPE child) {
+            LogicalProperties logicalProperties, CHILD_TYPE child) {
         super(PlanType.PHYSICAL_PROJECT, groupExpression, logicalProperties, child);
         this.projects = Objects.requireNonNull(projects, "projects can not be null");
     }
@@ -58,6 +58,24 @@ public class PhysicalProject<CHILD_TYPE extends Plan> extends PhysicalUnary<CHIL
         return "Project (" + StringUtils.join(projects, ", ") + ")";
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PhysicalProject that = (PhysicalProject) o;
+        return projects.equals(that.projects);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(projects);
+    }
+
+
     @Override
     public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
         return visitor.visitPhysicalProject((PhysicalProject<Plan>) this, context);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalRelation.java
index 6faee76563..cce3e3a5e9 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalRelation.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalRelation.java
@@ -52,6 +52,23 @@ public abstract class PhysicalRelation extends PhysicalLeaf {
         return qualifier;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PhysicalRelation that = (PhysicalRelation) o;
+        return Objects.equals(qualifier, that.qualifier);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(qualifier);
+    }
+
     @Override
     public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
         return visitor.visitPhysicalScan(this, context);
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/EqualsTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/EqualsTest.java
new file mode 100644
index 0000000000..66de8b19be
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/EqualsTest.java
@@ -0,0 +1,226 @@
+// 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.doris.nereids.trees.plans;
+
+import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.catalog.Table;
+import org.apache.doris.catalog.TableIf.TableType;
+import org.apache.doris.nereids.properties.LogicalProperties;
+import org.apache.doris.nereids.properties.OrderKey;
+import org.apache.doris.nereids.trees.expressions.EqualTo;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Literal;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
+import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+import org.apache.doris.nereids.trees.plans.logical.LogicalSort;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalAggregate;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
+import org.apache.doris.nereids.types.BigIntType;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import mockit.Mocked;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Optional;
+
+// TODO: need more detailed test
+public class EqualsTest {
+    /* *************************** Logical *************************** */
+    @Test
+    public void testLogicalAggregate(@Mocked Plan child) {
+        List<Expression> groupByExprList = Lists.newArrayList();
+        List<NamedExpression> outputExpressionList = ImmutableList.of(
+                new SlotReference("a", new BigIntType(), true, Lists.newArrayList())
+        );
+
+        LogicalAggregate one = new LogicalAggregate(groupByExprList, outputExpressionList, child);
+        Assert.assertEquals(one, one);
+
+        List<Expression> groupByExprList1 = Lists.newArrayList();
+        List<NamedExpression> outputExpressionList1 = ImmutableList.of(
+                new SlotReference("b", new BigIntType(), true, Lists.newArrayList())
+        );
+
+        LogicalAggregate two = new LogicalAggregate(groupByExprList1, outputExpressionList1, child);
+        Assert.assertNotEquals(one, two);
+    }
+
+    @Test
+    public void testLogicalFilter(@Mocked Plan child) {
+        Expression predicate = new EqualTo(Literal.of(1), Literal.of(2));
+        LogicalFilter logicalFilter = new LogicalFilter(predicate, child);
+        Assert.assertEquals(logicalFilter, logicalFilter);
+
+        Expression predicate1 = new EqualTo(Literal.of(1), Literal.of(1));
+        LogicalFilter logicalFilter1 = new LogicalFilter(predicate1, child);
+        Assert.assertNotEquals(logicalFilter, logicalFilter1);
+    }
+
+    @Test
+    public void testLogicalJoin(@Mocked Plan left, @Mocked Plan right) {
+        Expression condition = new EqualTo(
+                new SlotReference("a", new BigIntType(), true, Lists.newArrayList()),
+                new SlotReference("b", new BigIntType(), true, Lists.newArrayList())
+        );
+        LogicalJoin innerJoin = new LogicalJoin(JoinType.INNER_JOIN, Optional.of(condition), left, right);
+        Assert.assertEquals(innerJoin, innerJoin);
+
+        // Notice: condition1 != condition, so following is `assertNotEquals`.
+        // Because SlotReference.exprId is UUID.
+        Expression condition1 = new EqualTo(
+                new SlotReference("a", new BigIntType(), true, Lists.newArrayList()),
+                new SlotReference("b", new BigIntType(), true, Lists.newArrayList())
+        );
+        LogicalJoin innerJoin1 = new LogicalJoin(JoinType.INNER_JOIN, Optional.of(condition1), left, right);
+        Assert.assertNotEquals(innerJoin, innerJoin1);
+
+        Expression condition2 = new EqualTo(
+                new SlotReference("a", new BigIntType(), false, Lists.newArrayList()),
+                new SlotReference("b", new BigIntType(), true, Lists.newArrayList())
+        );
+        LogicalJoin innerJoin2 = new LogicalJoin(JoinType.INNER_JOIN, Optional.of(condition2), left, right);
+        Assert.assertNotEquals(innerJoin, innerJoin2);
+    }
+
+    @Test
+    public void testLogicalOlapScan() {
+        LogicalOlapScan olapScan = new LogicalOlapScan(new Table(TableType.OLAP), Lists.newArrayList());
+        Assert.assertEquals(olapScan, olapScan);
+
+        LogicalOlapScan olapScan1 = new LogicalOlapScan(new Table(TableType.OLAP), Lists.newArrayList());
+        Assert.assertEquals(olapScan, olapScan1);
+    }
+
+    @Test
+    public void testLogicalProject(@Mocked Plan child) {
+        // TODO: Depend on NamedExpression Equals
+        SlotReference aSlot = new SlotReference("a", new BigIntType(), true, Lists.newArrayList());
+        List<NamedExpression> projects = ImmutableList.of(aSlot);
+        LogicalProject logicalProject = new LogicalProject(projects, child);
+        Assert.assertEquals(logicalProject, logicalProject);
+
+        LogicalProject logicalProjectWithSameSlot = new LogicalProject(ImmutableList.of(aSlot), child);
+        Assert.assertEquals(logicalProject, logicalProjectWithSameSlot);
+
+        SlotReference a1Slot = new SlotReference("a", new BigIntType(), true, Lists.newArrayList());
+        LogicalProject a1LogicalProject = new LogicalProject(ImmutableList.of(a1Slot), child);
+        Assert.assertNotEquals(logicalProject, a1LogicalProject);
+
+        SlotReference bSlot = new SlotReference("b", new BigIntType(), true, Lists.newArrayList());
+        LogicalProject bLogicalProject1 = new LogicalProject(ImmutableList.of(bSlot), child);
+        Assert.assertNotEquals(logicalProject, bLogicalProject1);
+    }
+
+    @Test
+    public void testLogicalSort(@Mocked Plan child) {
+        // TODO: Depend on List<OrderKey> Equals
+        List<OrderKey> orderKeyList = Lists.newArrayList();
+        LogicalSort logicalSort = new LogicalSort(orderKeyList, child);
+        Assert.assertEquals(logicalSort, logicalSort);
+
+        List<OrderKey> orderKeyListClone = Lists.newArrayList();
+        LogicalSort logicalSortClone = new LogicalSort(orderKeyListClone, child);
+        Assert.assertEquals(logicalSort, logicalSortClone);
+    }
+
+    /* *************************** Physical *************************** */
+    @Test
+    public void testPhysicalAggregate(@Mocked Plan child, @Mocked LogicalProperties logicalProperties) {
+        List<Expression> groupByExprList = Lists.newArrayList();
+        SlotReference slotReference = new SlotReference("a", new BigIntType(), true, Lists.newArrayList());
+        List<NamedExpression> outputExpressionList = ImmutableList.of(slotReference);
+        List<Expression> partitionExprList = Lists.newArrayList();
+        AggPhase aggPhase = AggPhase.LOCAL;
+        boolean usingStream = true;
+
+        PhysicalAggregate physicalAggregate = new PhysicalAggregate(groupByExprList, outputExpressionList,
+                partitionExprList, aggPhase, usingStream, logicalProperties, child);
+        Assert.assertEquals(physicalAggregate, physicalAggregate);
+    }
+
+    @Test
+    public void testPhysicalFilter(@Mocked Plan child, @Mocked LogicalProperties logicalProperties) {
+        Expression predicate = new EqualTo(Literal.of(1), Literal.of(2));
+
+        PhysicalFilter physicalFilter = new PhysicalFilter(predicate, logicalProperties, child);
+        Assert.assertEquals(physicalFilter, physicalFilter);
+    }
+
+    @Test
+    public void testPhysicalJoin(@Mocked Plan left, @Mocked Plan right, @Mocked LogicalProperties logicalProperties) {
+        Expression expression = new EqualTo(Literal.of(1), Literal.of(2));
+
+        PhysicalHashJoin innerJoin = new PhysicalHashJoin(JoinType.INNER_JOIN, Optional.of(expression),
+                logicalProperties, left,
+                right);
+        Assert.assertEquals(innerJoin, innerJoin);
+    }
+
+    @Test
+    public void testPhysicalOlapScan(@Mocked LogicalProperties logicalProperties, @Mocked OlapTable olapTable) {
+        List<String> qualifier = Lists.newArrayList();
+
+        PhysicalOlapScan olapScan = new PhysicalOlapScan(olapTable, qualifier, Optional.empty(), logicalProperties);
+
+        Assert.assertEquals(olapScan, olapScan);
+    }
+
+    @Test
+    public void testPhysicalProject(@Mocked Plan child, @Mocked LogicalProperties logicalProperties) {
+
+        // TODO: Depend on NamedExpression Equals
+        SlotReference aSlot = new SlotReference("a", new BigIntType(), true, Lists.newArrayList());
+        List<NamedExpression> projects = ImmutableList.of(aSlot);
+        PhysicalProject physicalProject = new PhysicalProject(projects, logicalProperties, child);
+        Assert.assertEquals(physicalProject, physicalProject);
+
+        PhysicalProject physicalProjectWithSameSlot = new PhysicalProject(ImmutableList.of(aSlot), logicalProperties,
+                child);
+        Assert.assertEquals(physicalProject, physicalProjectWithSameSlot);
+
+        SlotReference a1Slot = new SlotReference("a", new BigIntType(), true, Lists.newArrayList());
+        PhysicalProject a1PhysicalProject = new PhysicalProject(ImmutableList.of(a1Slot), logicalProperties, child);
+        Assert.assertNotEquals(physicalProject, a1PhysicalProject);
+    }
+
+    @Test
+    public void testPhysicalSort(@Mocked Plan child, @Mocked LogicalProperties logicalProperties) {
+        // TODO: Depend on List<OrderKey> Equals
+        List<OrderKey> orderKeyList = Lists.newArrayList();
+
+        PhysicalHeapSort physicalHeapSort = new PhysicalHeapSort(orderKeyList, -1, 0, logicalProperties, child);
+        Assert.assertEquals(physicalHeapSort, physicalHeapSort);
+
+        List<OrderKey> orderKeyListClone = Lists.newArrayList();
+        PhysicalHeapSort physicalHeapSortClone = new PhysicalHeapSort(orderKeyListClone, -1, 0, logicalProperties,
+                child);
+        Assert.assertEquals(physicalHeapSort, physicalHeapSortClone);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org