You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2019/06/01 23:27:28 UTC

[calcite] 01/01: Complete [CALCITE-2969] and [CALCITE-3102] by restoring APIs that use SemiJoin but mask deprecation warnings

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

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

commit ef0c4c6ddb7553e2e858259007d8ca1cb3692101
Author: Julian Hyde <jh...@apache.org>
AuthorDate: Fri May 31 17:47:17 2019 -0700

    Complete [CALCITE-2969] and [CALCITE-3102] by restoring APIs that use SemiJoin but mask deprecation warnings
    
    Fix description of RelBuilder.semiJoin algebra.md.
---
 .../enumerable/EnumerableMergeJoinRule.java        |  6 +-
 .../adapter/enumerable/EnumerableRules.java        |  4 +-
 .../adapter/enumerable/EnumerableSemiJoin.java     | 91 +++++++++++++++++++---
 .../adapter/enumerable/EnumerableSemiJoinRule.java | 23 ++----
 .../org/apache/calcite/rel/core/Correlate.java     | 20 +++--
 .../calcite/rel/logical/LogicalCorrelate.java      | 16 ++++
 .../calcite/rel/metadata/RelMdCollation.java       |  8 ++
 .../rel/metadata/RelMdColumnUniqueness.java        |  9 +++
 .../rel/metadata/RelMdDistinctRowCount.java        |  7 ++
 .../calcite/rel/metadata/RelMdNodeTypes.java       |  7 ++
 .../calcite/rel/metadata/RelMdPopulationSize.java  |  6 ++
 .../apache/calcite/rel/metadata/RelMdRowCount.java | 16 +++-
 .../org/apache/calcite/rel/metadata/RelMdSize.java |  6 ++
 .../calcite/rel/metadata/RelMdUniqueKeys.java      |  8 ++
 .../org/apache/calcite/rel/metadata/RelMdUtil.java | 18 ++++-
 .../apache/calcite/rel/mutable/MutableRels.java    | 15 ++++
 .../calcite/rel/rules/JoinToCorrelateRule.java     | 17 ++--
 .../java/org/apache/calcite/tools/Programs.java    |  4 +
 site/_docs/algebra.md                              |  2 +-
 site/_docs/history.md                              |  1 +
 20 files changed, 240 insertions(+), 44 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java
index 2b04efd..44e4798 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableMergeJoinRule.java
@@ -85,13 +85,13 @@ class EnumerableMergeJoinRule extends ConverterRule {
     final RelOptCluster cluster = join.getCluster();
     RelNode newRel;
     try {
-      RelTraitSet traits = join.getTraitSet()
+      RelTraitSet traitSet = join.getTraitSet()
           .replace(EnumerableConvention.INSTANCE);
       if (!collations.isEmpty()) {
-        traits = traits.replace(collations);
+        traitSet = traitSet.replace(collations);
       }
       newRel = new EnumerableMergeJoin(cluster,
-          traits,
+          traitSet,
           left,
           right,
           info.getEquiCondition(left, right, cluster.getRexBuilder()),
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java
index e7f4bc6..19d30bf 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableRules.java
@@ -44,7 +44,9 @@ public class EnumerableRules {
   public static final RelOptRule ENUMERABLE_MERGE_JOIN_RULE =
       new EnumerableMergeJoinRule();
 
-  @Deprecated // To be removed before 2.0, use ENUMERABLE_JOIN_RULE instead.
+  /** @deprecated To be removed along with {@link SemiJoin};
+   * use {@link #ENUMERABLE_JOIN_RULE} */
+  @Deprecated // to be removed before 1.21
   public static final RelOptRule ENUMERABLE_SEMI_JOIN_RULE =
       new EnumerableSemiJoinRule();
 
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java
index 691e79a..cde97b6 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoin.java
@@ -16,27 +16,35 @@
  */
 package org.apache.calcite.adapter.enumerable;
 
+import org.apache.calcite.linq4j.tree.BlockBuilder;
+import org.apache.calcite.linq4j.tree.Expression;
+import org.apache.calcite.linq4j.tree.Expressions;
 import org.apache.calcite.plan.RelOptCluster;
+import org.apache.calcite.plan.RelOptCost;
+import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.InvalidRelException;
 import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.metadata.RelMdCollation;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ImmutableIntList;
-
-import com.google.common.collect.ImmutableSet;
+import org.apache.calcite.util.Util;
 
 /** Implementation of {@link org.apache.calcite.rel.core.SemiJoin} in
  * {@link org.apache.calcite.adapter.enumerable.EnumerableConvention enumerable calling convention}.
  *
- * @deprecated This class is deprecated, the function is merged into {@link EnumerableHashJoin},
+ * @deprecated This class is deprecated along with {@link SemiJoin};
+ * the function is merged into {@link EnumerableHashJoin};
  * see {@link EnumerableJoinRule} for details.
  */
-@Deprecated // to be removed before 2.0
-public class EnumerableSemiJoin extends EnumerableHashJoin implements EnumerableRel {
+@Deprecated // to be removed before 1.21
+public class EnumerableSemiJoin extends org.apache.calcite.rel.core.SemiJoin
+    implements EnumerableRel {
   /** Creates an EnumerableSemiJoin.
    *
    * <p>Use {@link #create} unless you know what you're doing. */
@@ -49,12 +57,11 @@ public class EnumerableSemiJoin extends EnumerableHashJoin implements Enumerable
       ImmutableIntList leftKeys,
       ImmutableIntList rightKeys)
       throws InvalidRelException {
-    super(cluster, traits, left, right, condition,
-        ImmutableSet.of(), JoinRelType.SEMI);
+    super(cluster, traits, left, right, condition, leftKeys, rightKeys);
   }
 
   /** Creates an EnumerableSemiJoin. */
-  public static EnumerableHashJoin create(RelNode left, RelNode right, RexNode condition,
+  public static EnumerableSemiJoin create(RelNode left, RelNode right, RexNode condition,
       ImmutableIntList leftKeys, ImmutableIntList rightKeys) {
     final RelOptCluster cluster = left.getCluster();
     final RelMetadataQuery mq = cluster.getMetadataQuery();
@@ -63,20 +70,82 @@ public class EnumerableSemiJoin extends EnumerableHashJoin implements Enumerable
             .replaceIfs(RelCollationTraitDef.INSTANCE,
                 () -> RelMdCollation.enumerableSemiJoin(mq, left, right));
     try {
-      return new EnumerableHashJoin(
+      return new EnumerableSemiJoin(
           cluster,
           traitSet,
           left,
           right,
           condition,
-          ImmutableSet.of(),
-          JoinRelType.SEMI);
+          leftKeys,
+          rightKeys);
+    } catch (InvalidRelException e) {
+      // Semantic error not possible. Must be a bug. Convert to
+      // internal error.
+      throw new AssertionError(e);
+    }
+  }
+
+  @Override public EnumerableSemiJoin copy(RelTraitSet traitSet,
+      RexNode condition, RelNode left, RelNode right, JoinRelType joinType,
+      boolean semiJoinDone) {
+    assert joinType == JoinRelType.INNER;
+    final JoinInfo joinInfo = JoinInfo.of(left, right, condition);
+    assert joinInfo.isEqui();
+    try {
+      return new EnumerableSemiJoin(getCluster(), traitSet, left, right,
+          condition, joinInfo.leftKeys, joinInfo.rightKeys);
     } catch (InvalidRelException e) {
       // Semantic error not possible. Must be a bug. Convert to
       // internal error.
       throw new AssertionError(e);
     }
   }
+
+  @Override public RelOptCost computeSelfCost(RelOptPlanner planner,
+      RelMetadataQuery mq) {
+    double rowCount = mq.getRowCount(this);
+
+    // Right-hand input is the "build", and hopefully small, input.
+    final double rightRowCount = right.estimateRowCount(mq);
+    final double leftRowCount = left.estimateRowCount(mq);
+    if (Double.isInfinite(leftRowCount)) {
+      rowCount = leftRowCount;
+    } else {
+      rowCount += Util.nLogN(leftRowCount);
+    }
+    if (Double.isInfinite(rightRowCount)) {
+      rowCount = rightRowCount;
+    } else {
+      rowCount += rightRowCount;
+    }
+    return planner.getCostFactory().makeCost(rowCount, 0, 0).multiplyBy(.01d);
+  }
+
+  public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
+    BlockBuilder builder = new BlockBuilder();
+    final Result leftResult =
+        implementor.visitChild(this, 0, (EnumerableRel) left, pref);
+    Expression leftExpression =
+        builder.append(
+            "left", leftResult.block);
+    final Result rightResult =
+        implementor.visitChild(this, 1, (EnumerableRel) right, pref);
+    Expression rightExpression =
+        builder.append(
+            "right", rightResult.block);
+    final PhysType physType = leftResult.physType;
+    return implementor.result(
+        physType,
+        builder.append(
+            Expressions.call(
+                BuiltInMethod.SEMI_JOIN.method,
+                Expressions.list(
+                    leftExpression,
+                    rightExpression,
+                    leftResult.physType.generateAccessor(leftKeys),
+                    rightResult.physType.generateAccessor(rightKeys))))
+            .toBlock());
+  }
 }
 
 // End EnumerableSemiJoin.java
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoinRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoinRule.java
index 631ea1e..cd54be4 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableSemiJoinRule.java
@@ -17,13 +17,8 @@
 package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.Convention;
-import org.apache.calcite.rel.InvalidRelException;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
-import org.apache.calcite.rel.core.JoinRelType;
-import org.apache.calcite.rel.core.SemiJoin;
-
-import com.google.common.collect.ImmutableSet;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -34,15 +29,16 @@ import java.util.List;
  *
  * @deprecated Use {@link EnumerableJoinRule} instead.
  */
-@Deprecated // to be removed before 2.0
+@Deprecated // to be removed before 1.21
 class EnumerableSemiJoinRule extends ConverterRule {
   EnumerableSemiJoinRule() {
-    super(SemiJoin.class, Convention.NONE, EnumerableConvention.INSTANCE,
-        "EnumerableSemiJoinRule");
+    super(org.apache.calcite.rel.core.SemiJoin.class, Convention.NONE,
+        EnumerableConvention.INSTANCE, "EnumerableSemiJoinRule");
   }
 
   @Override public RelNode convert(RelNode rel) {
-    final SemiJoin semiJoin = (SemiJoin) rel;
+    final org.apache.calcite.rel.core.SemiJoin semiJoin =
+        (org.apache.calcite.rel.core.SemiJoin) rel;
     final List<RelNode> newInputs = new ArrayList<>();
     for (RelNode input : semiJoin.getInputs()) {
       if (!(input.getConvention() instanceof EnumerableConvention)) {
@@ -52,13 +48,8 @@ class EnumerableSemiJoinRule extends ConverterRule {
       }
       newInputs.add(input);
     }
-    try {
-      return EnumerableHashJoin.create(newInputs.get(0), newInputs.get(1),
-          semiJoin.getCondition(), ImmutableSet.of(), JoinRelType.SEMI);
-    } catch (InvalidRelException e) {
-      // Convert to internal error.
-      throw new AssertionError(e);
-    }
+    return EnumerableSemiJoin.create(newInputs.get(0), newInputs.get(1),
+        semiJoin.getCondition(), semiJoin.leftKeys, semiJoin.rightKeys);
   }
 }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Correlate.java b/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
index 44a8534..445bfe7 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Correlate.java
@@ -35,6 +35,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -85,17 +86,26 @@ public abstract class Correlate extends BiRel {
    */
   protected Correlate(
       RelOptCluster cluster,
-      RelTraitSet traits,
+      RelTraitSet traitSet,
       RelNode left,
       RelNode right,
       CorrelationId correlationId,
       ImmutableBitSet requiredColumns,
       JoinRelType joinType) {
-    super(cluster, traits, left, right);
+    super(cluster, traitSet, left, right);
     assert !joinType.generatesNullsOnLeft() : "Correlate has invalid join type " + joinType;
-    this.joinType = joinType;
-    this.correlationId = correlationId;
-    this.requiredColumns = requiredColumns;
+    this.joinType = Objects.requireNonNull(joinType);
+    this.correlationId = Objects.requireNonNull(correlationId);
+    this.requiredColumns = Objects.requireNonNull(requiredColumns);
+  }
+
+  @Deprecated // to be removed before 1.21
+  protected Correlate(RelOptCluster cluster, RelTraitSet traitSet,
+      RelNode left, RelNode right, CorrelationId correlationId,
+      ImmutableBitSet requiredColumns,
+      org.apache.calcite.sql.SemiJoinType joinType) {
+    this(cluster, traitSet, left, right, correlationId, requiredColumns,
+        joinType.toJoinType());
   }
 
   /**
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
index 137ca78..7fb3720 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalCorrelate.java
@@ -74,6 +74,15 @@ public final class LogicalCorrelate extends Correlate {
     assert !CalciteSystemProperty.DEBUG.value() || isValid(Litmus.THROW, null);
   }
 
+  @Deprecated // to be removed before 1.21
+  public LogicalCorrelate(RelOptCluster cluster, RelTraitSet traitSet,
+      RelNode left, RelNode right, CorrelationId correlationId,
+      ImmutableBitSet requiredColumns,
+      org.apache.calcite.sql.SemiJoinType joinType) {
+    this(cluster, traitSet, left, right, correlationId, requiredColumns,
+        joinType.toJoinType());
+  }
+
   /**
    * Creates a LogicalCorrelate by parsing serialized output.
    */
@@ -95,6 +104,13 @@ public final class LogicalCorrelate extends Correlate {
         requiredColumns, joinType);
   }
 
+  @Deprecated // to be removed before 1.21
+  public static LogicalCorrelate create(RelNode left, RelNode right,
+      CorrelationId correlationId, ImmutableBitSet requiredColumns,
+      org.apache.calcite.sql.SemiJoinType joinType) {
+    return create(left, right, correlationId, requiredColumns, joinType.toJoinType());
+  }
+
   //~ Methods ----------------------------------------------------------------
 
   @Override public LogicalCorrelate copy(RelTraitSet traitSet,
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index e1edf51..6da79ce 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -155,6 +155,14 @@ public class RelMdCollation
             join.getJoinType()));
   }
 
+  @Deprecated // to be removed before 1.21
+  public ImmutableList<RelCollation> collations(
+      org.apache.calcite.adapter.enumerable.EnumerableSemiJoin join,
+      RelMetadataQuery mq) {
+    return ImmutableList.copyOf(
+        RelMdCollation.enumerableSemiJoin(mq, join.getLeft(), join.getRight()));
+  }
+
   public ImmutableList<RelCollation> collations(Sort sort,
       RelMetadataQuery mq) {
     return ImmutableList.copyOf(
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
index dce0564..0ae9684 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java
@@ -312,6 +312,15 @@ public class RelMdColumnUniqueness
     throw new AssertionError();
   }
 
+  @Deprecated // to be removed before 1.21
+  public Boolean areColumnsUnique(
+      org.apache.calcite.rel.core.SemiJoin rel, RelMetadataQuery mq,
+      ImmutableBitSet columns, boolean ignoreNulls) {
+    // only return the unique keys from the LHS since a semijoin only
+    // returns the LHS
+    return mq.areColumnsUnique(rel.getLeft(), columns, ignoreNulls);
+  }
+
   public Boolean areColumnsUnique(Aggregate rel, RelMetadataQuery mq,
       ImmutableBitSet columns, boolean ignoreNulls) {
     // group by keys form a unique key
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
index 0cca9a4..688eb2a 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistinctRowCount.java
@@ -142,6 +142,13 @@ public class RelMdDistinctRowCount
         groupKey, predicate, false);
   }
 
+  @Deprecated // to be removed before 1.21
+  public Double getDistinctRowCount(
+      org.apache.calcite.rel.core.SemiJoin rel, RelMetadataQuery mq,
+      ImmutableBitSet groupKey, RexNode predicate) {
+    return RelMdUtil.getSemiJoinDistinctRowCount(rel, mq, groupKey, predicate);
+  }
+
   public Double getDistinctRowCount(Aggregate rel, RelMetadataQuery mq,
       ImmutableBitSet groupKey, RexNode predicate) {
     if (predicate == null || predicate.isAlwaysTrue()) {
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdNodeTypes.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdNodeTypes.java
index 22737b6..c9052a1 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdNodeTypes.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdNodeTypes.java
@@ -113,6 +113,13 @@ public class RelMdNodeTypes
     return getNodeTypes(rel, Join.class, mq);
   }
 
+  @Deprecated // to be removed before 1.21
+  public Multimap<Class<? extends RelNode>, RelNode> getNodeTypes(
+      org.apache.calcite.rel.core.SemiJoin rel,
+      RelMetadataQuery mq) {
+    return getNodeTypes(rel, org.apache.calcite.rel.core.SemiJoin.class, mq);
+  }
+
   public Multimap<Class<? extends RelNode>, RelNode> getNodeTypes(Aggregate rel,
       RelMetadataQuery mq) {
     return getNodeTypes(rel, Aggregate.class, mq);
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
index 8e21963..f1adadf 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
@@ -84,6 +84,12 @@ public class RelMdPopulationSize
     return RelMdUtil.getJoinPopulationSize(mq, rel, groupKey);
   }
 
+  @Deprecated // to be removed before 1.21
+  public Double getPopulationSize(org.apache.calcite.rel.core.SemiJoin rel,
+      RelMetadataQuery mq, ImmutableBitSet groupKey) {
+    return mq.getPopulationSize(rel.getLeft(), groupKey);
+  }
+
   public Double getPopulationSize(Aggregate rel, RelMetadataQuery mq,
       ImmutableBitSet groupKey) {
     ImmutableBitSet.Builder childKey = ImmutableBitSet.builder();
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
index 27db782..be01204 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
@@ -33,6 +33,7 @@ import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rex.RexDynamicParam;
 import org.apache.calcite.rex.RexLiteral;
+import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.util.Bug;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ImmutableBitSet;
@@ -186,8 +187,21 @@ public class RelMdRowCount
     return RelMdUtil.getJoinRowCount(mq, rel, rel.getCondition());
   }
 
+  @Deprecated // to be removed before 1.21
+  public Double getRowCount(org.apache.calcite.rel.core.SemiJoin rel,
+      RelMetadataQuery mq) {
+    // create a RexNode representing the selectivity of the
+    // semijoin filter and pass it to getSelectivity
+    RexNode semiJoinSelectivity =
+        RelMdUtil.makeSemiJoinSelectivityRexNode(mq, rel);
+
+    return NumberUtil.multiply(
+        mq.getSelectivity(rel.getLeft(), semiJoinSelectivity),
+        mq.getRowCount(rel.getLeft()));
+  }
+
   public Double getRowCount(Aggregate rel, RelMetadataQuery mq) {
-    ImmutableBitSet groupKey = rel.getGroupSet(); // .range(rel.getGroupCount());
+    ImmutableBitSet groupKey = rel.getGroupSet();
 
     // rowCount is the cardinality of the group by columns
     Double distinctRowCount =
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
index c12c462..4233373 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSize.java
@@ -176,6 +176,12 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
     return list.build();
   }
 
+  @Deprecated // to be removed before 1.21
+  public List<Double> averageColumnSizes(
+      org.apache.calcite.rel.core.SemiJoin rel, RelMetadataQuery mq) {
+    return averageJoinColumnSizes(rel, mq);
+  }
+
   public List<Double> averageColumnSizes(Join rel, RelMetadataQuery mq) {
     return averageJoinColumnSizes(rel, mq);
   }
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java
index d33873e..6c13b0b 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java
@@ -205,6 +205,14 @@ public class RelMdUniqueKeys
     return retSet;
   }
 
+  @Deprecated // to be removed before 1.21
+  public Set<ImmutableBitSet> getUniqueKeys(org.apache.calcite.rel.core.SemiJoin rel,
+      RelMetadataQuery mq, boolean ignoreNulls) {
+    // only return the unique keys from the LHS since a semijoin only
+    // returns the LHS
+    return mq.getUniqueKeys(rel.getLeft(), ignoreNulls);
+  }
+
   public Set<ImmutableBitSet> getUniqueKeys(Aggregate rel, RelMetadataQuery mq,
       boolean ignoreNulls) {
     // group by keys form a unique key
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
index 2d308da..52ab057 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
@@ -110,6 +110,22 @@ public class RelMdUtil {
    * table/columns and the number of distinct values in the fact table
    * columns.
    *
+   * @param rel semijoin rel
+   * @return calculated selectivity
+   */
+  @Deprecated // to be removed before 1.21
+  public static double computeSemiJoinSelectivity(RelMetadataQuery mq,
+      org.apache.calcite.rel.core.SemiJoin rel) {
+    return computeSemiJoinSelectivity(mq, rel.getLeft(), rel.getRight(),
+        rel.getLeftKeys(), rel.getRightKeys());
+  }
+
+  /**
+   * Computes the selectivity of a semijoin filter if it is applied on a fact
+   * table. The computation is based on the selectivity of the dimension
+   * table/columns and the number of distinct values in the fact table
+   * columns.
+   *
    * @param factRel fact table participating in the semijoin
    * @param dimRel  dimension table participating in the semijoin
    * @param rel     semijoin rel
@@ -723,7 +739,7 @@ public class RelMdUtil {
   }
 
   /** Returns an estimate of the number of rows returned by a
-   * join with type {@link JoinRelType#SEMI}. */
+   * {@link SemiJoin}. */
   public static Double getSemiJoinRowCount(RelMetadataQuery mq, RelNode left,
       RelNode right, JoinRelType joinType, RexNode condition) {
     final Double leftCount = mq.getRowCount(left);
diff --git a/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java b/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
index 2428279..8d52c98 100644
--- a/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
+++ b/core/src/main/java/org/apache/calcite/rel/mutable/MutableRels.java
@@ -279,6 +279,7 @@ public abstract class MutableRels {
         mutableRel -> fromMutable(mutableRel, relBuilder));
   }
 
+  @SuppressWarnings("deprecation") // directive to be removed before 1.21
   public static MutableRel toMutable(RelNode rel) {
     if (rel instanceof HepRelVertex) {
       return toMutable(((HepRelVertex) rel).getCurrentRel());
@@ -360,6 +361,20 @@ public abstract class MutableRels {
           tableFunctionScan.getRowType(), inputs, tableFunctionScan.getCall(),
           tableFunctionScan.getElementType(), tableFunctionScan.getColumnMappings());
     }
+    // It is necessary that SemiJoin is placed in front of Join here, since SemiJoin
+    // is a sub-class of Join.
+    //
+    // NOTE: SemiJoin is deprecated and wil be removed before 1.21; when you
+    // remove the following lines, also remove the 'SuppressWarnings'
+    // directive at the top of this method.
+    if (rel instanceof org.apache.calcite.rel.core.SemiJoin) {
+      final org.apache.calcite.rel.core.SemiJoin semiJoin =
+          (org.apache.calcite.rel.core.SemiJoin) rel;
+      final MutableRel left = toMutable(semiJoin.getLeft());
+      final MutableRel right = toMutable(semiJoin.getRight());
+      return MutableSemiJoin.of(semiJoin.getRowType(), left, right,
+          semiJoin.getCondition(), semiJoin.getLeftKeys(), semiJoin.getRightKeys());
+    }
     if (rel instanceof Join) {
       final Join join = (Join) rel;
       final MutableRel left = toMutable(join.getLeft());
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
index d1476dd..8f5de4b 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinToCorrelateRule.java
@@ -66,17 +66,23 @@ public class JoinToCorrelateRule extends RelOptRule {
    */
   public static final JoinToCorrelateRule INSTANCE =
       new JoinToCorrelateRule(LogicalJoin.class, RelFactories.LOGICAL_BUILDER,
-              "JoinToCorrelateRule");
+          "JoinToCorrelateRule");
 
-  @Deprecated // To be removed before 2.0, should use INSTANCE instead.
+  /** Synonym for {@link #INSTANCE};
+   * {@code JOIN} is not deprecated, but {@code INSTANCE} is preferred. */
   public static final JoinToCorrelateRule JOIN = INSTANCE;
 
   /**
    * Rule that converts a {@link org.apache.calcite.rel.core.SemiJoin}
    * into a {@link org.apache.calcite.rel.logical.LogicalCorrelate}
+   *
+   * @deprecated Will be unnecessary when {@code SemiJoin} is removed before
+   * 1.21, and will be removed at that time.
    */
-  @Deprecated // To be removed before 2.0, should use INSTANCE instead.
-  public static final JoinToCorrelateRule SEMI = INSTANCE;
+  @Deprecated // to be removed before 1.21
+  public static final JoinToCorrelateRule SEMI =
+      new JoinToCorrelateRule(org.apache.calcite.rel.core.SemiJoin.class,
+          RelFactories.LOGICAL_BUILDER, "SemiJoinToCorrelateRule");
 
   //~ Constructors -----------------------------------------------------------
 
@@ -96,7 +102,8 @@ public class JoinToCorrelateRule extends RelOptRule {
   /**
    * Creates a JoinToCorrelateRule for a certain sub-class of
    * {@link org.apache.calcite.rel.core.Join} to be transformed into a
-   * {@link org.apache.calcite.rel.logical.LogicalCorrelate}
+   * {@link org.apache.calcite.rel.logical.LogicalCorrelate}.
+   *
    * @param clazz Class of relational expression to match (must not be null)
    * @param relBuilderFactory Builder for relational expressions
    * @param description Description, or null to guess description
diff --git a/core/src/main/java/org/apache/calcite/tools/Programs.java b/core/src/main/java/org/apache/calcite/tools/Programs.java
index 819aee4..fb1abfa 100644
--- a/core/src/main/java/org/apache/calcite/tools/Programs.java
+++ b/core/src/main/java/org/apache/calcite/tools/Programs.java
@@ -82,10 +82,14 @@ public class Programs {
   public static final Program SUB_QUERY_PROGRAM =
       subQuery(DefaultRelMetadataProvider.INSTANCE);
 
+  @SuppressWarnings("deprecation") // directive to be removed before 1.21
   public static final ImmutableSet<RelOptRule> RULE_SET =
       ImmutableSet.of(
           EnumerableRules.ENUMERABLE_JOIN_RULE,
           EnumerableRules.ENUMERABLE_MERGE_JOIN_RULE,
+          // The following line is to be removed before 1.21;
+          // when it is removed, also remove SuppressWarnings directive, above
+          EnumerableRules.ENUMERABLE_SEMI_JOIN_RULE,
           EnumerableRules.ENUMERABLE_CORRELATE_RULE,
           EnumerableRules.ENUMERABLE_PROJECT_RULE,
           EnumerableRules.ENUMERABLE_FILTER_RULE,
diff --git a/site/_docs/algebra.md b/site/_docs/algebra.md
index 2ada663..a66eed2 100644
--- a/site/_docs/algebra.md
+++ b/site/_docs/algebra.md
@@ -322,7 +322,7 @@ return the `RelBuilder`.
 | `exchange(distribution)` | Creates an [Exchange]({{ site.apiRoot }}/org/apache/calcite/rel/core/Exchange.html).
 | `sortExchange(distribution, collation)` | Creates a [SortExchange]({{ site.apiRoot }}/org/apache/calcite/rel/core/SortExchange.html).
 | `join(joinType, expr...)`<br/>`join(joinType, exprList)`<br/>`join(joinType, fieldName...)` | Creates a [Join]({{ site.apiRoot }}/org/apache/calcite/rel/core/Join.html) of the two most recent relational expressions.<br/><br/>The first form joins on a boolean expression (multiple conditions are combined using AND).<br/><br/>The last form joins on named fields; each side must have a field of each name.
-| `semiJoin(expr)` | Creates a [SemiJoin]({{ site.apiRoot }}/org/apache/calcite/rel/core/SemiJoin.html) of the two most recent relational expressions.
+| `semiJoin(expr)` | Creates a [Join]({{ site.apiRoot }}/org/apache/calcite/rel/core/Join.html) with SEMI join type of the two most recent relational expressions.
 | `antiJoin(expr)` | Creates an AntiJoin of the two most recent relational expressions.
 | `union(all [, n])` | Creates a [Union]({{ site.apiRoot }}/org/apache/calcite/rel/core/Union.html) of the `n` (default two) most recent relational expressions.
 | `intersect(all [, n])` | Creates an [Intersect]({{ site.apiRoot }}/org/apache/calcite/rel/core/Intersect.html) of the `n` (default two) most recent relational expressions.
diff --git a/site/_docs/history.md b/site/_docs/history.md
index 8b82946..a5d575e 100644
--- a/site/_docs/history.md
+++ b/site/_docs/history.md
@@ -41,6 +41,7 @@ other software versions as specified in `pom.xml`.
 
 #### Breaking Changes
 
+* Make `EnumerableMergeJoin` extend `Join` instead of `EquiJoin`
 * `Correlate` use `JoinRelType` instead of `SemiJoinType`
 * Rename `EnumerableThetaJoin` to `EnumerableNestedLoopJoin`
 * Rename `EnumerableJoin` to `EnumerableHashJoin`