You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by ch...@apache.org on 2022/08/09 07:26:08 UTC

[calcite] branch main updated: [CALCITE-4223] Metadata handlers for TableScan should see whether the RelOptTable implements the handler

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 7e0057e8de [CALCITE-4223] Metadata handlers for TableScan should see whether the RelOptTable implements the handler
7e0057e8de is described below

commit 7e0057e8de93930f1b2952a1cbcee8ad7a6bfb4b
Author: chunwei.lcw <ch...@gmail.com>
AuthorDate: Wed May 18 09:41:29 2022 +0800

    [CALCITE-4223] Metadata handlers for TableScan should see whether the RelOptTable implements the handler
---
 .../calcite/rel/metadata/RelMdCollation.java       |  5 ++
 .../calcite/rel/metadata/RelMdColumnOrigins.java   | 11 +++
 .../rel/metadata/RelMdColumnUniqueness.java        |  9 ++-
 .../rel/metadata/RelMdDistinctRowCount.java        | 11 +++
 .../calcite/rel/metadata/RelMdDistribution.java    |  5 ++
 .../rel/metadata/RelMdExplainVisibility.java       | 12 ++++
 .../rel/metadata/RelMdExpressionLineage.java       |  6 ++
 .../calcite/rel/metadata/RelMdMaxRowCount.java     |  7 +-
 .../calcite/rel/metadata/RelMdMinRowCount.java     |  7 +-
 .../calcite/rel/metadata/RelMdNodeTypes.java       |  5 ++
 .../calcite/rel/metadata/RelMdParallelism.java     |  5 ++
 .../rel/metadata/RelMdPercentageOriginalRows.java  | 10 +++
 .../calcite/rel/metadata/RelMdPopulationSize.java  | 11 +++
 .../calcite/rel/metadata/RelMdPredicates.java      |  7 +-
 .../apache/calcite/rel/metadata/RelMdRowCount.java |  7 +-
 .../calcite/rel/metadata/RelMdSelectivity.java     | 11 +++
 .../org/apache/calcite/rel/metadata/RelMdSize.java |  7 +-
 .../calcite/rel/metadata/RelMdTableReferences.java |  5 ++
 .../calcite/rel/metadata/RelMdUniqueKeys.java      |  6 ++
 .../org/apache/calcite/test/RelMetadataTest.java   | 78 ++++++++++++++++++++++
 .../GeneratedMetadata_ColumnOriginHandler.java     |  2 +
 .../GeneratedMetadata_DistinctRowCountHandler.java |  2 +
 ...GeneratedMetadata_ExplainVisibilityHandler.java |  4 +-
 ...atedMetadata_PercentageOriginalRowsHandler.java |  2 +
 .../GeneratedMetadata_PopulationSizeHandler.java   |  2 +
 .../GeneratedMetadata_SelectivityHandler.java      |  2 +
 .../calcite/test/catalog/MockCatalogReader.java    |  2 +-
 27 files changed, 232 insertions(+), 9 deletions(-)

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 e32ad62c51..537099d9c9 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
@@ -149,6 +149,11 @@ public class RelMdCollation
 
   public @Nullable ImmutableList<RelCollation> collations(TableScan scan,
       RelMetadataQuery mq) {
+    final BuiltInMetadata.Collation.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.Collation.Handler.class);
+    if (handler != null) {
+      return handler.collations(scan, mq);
+    }
     return copyOf(table(scan.getTable()));
   }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnOrigins.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnOrigins.java
index 02bb8919fd..dc30e6a20a 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnOrigins.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnOrigins.java
@@ -30,6 +30,7 @@ import org.apache.calcite.rel.core.Snapshot;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.TableFunctionScan;
 import org.apache.calcite.rel.core.TableModify;
+import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
@@ -164,6 +165,16 @@ public class RelMdColumnOrigins
     return createDerivedColumnOrigins(set);
   }
 
+  public @Nullable Set<RelColumnOrigin> getColumnOrigins(TableScan scan,
+      RelMetadataQuery mq, int iOutputColumn) {
+    final BuiltInMetadata.ColumnOrigin.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.ColumnOrigin.Handler.class);
+    if (handler != null) {
+      return handler.getColumnOrigins(scan, mq, iOutputColumn);
+    }
+    return getColumnOrigins((RelNode) scan, mq, iOutputColumn);
+  }
+
   public @Nullable Set<RelColumnOrigin> getColumnOrigins(Filter rel,
       RelMetadataQuery mq, int iOutputColumn) {
     return mq.getColumnOrigins(rel.getInput(), iOutputColumn);
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 aef93c3a55..50217699c3 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
@@ -78,9 +78,14 @@ public class RelMdColumnUniqueness
     return BuiltInMetadata.ColumnUniqueness.DEF;
   }
 
-  public Boolean areColumnsUnique(TableScan rel, RelMetadataQuery mq,
+  public Boolean areColumnsUnique(TableScan scan, RelMetadataQuery mq,
       ImmutableBitSet columns, boolean ignoreNulls) {
-    return rel.getTable().isKey(columns);
+    final BuiltInMetadata.ColumnUniqueness.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.ColumnUniqueness.Handler.class);
+    if (handler != null) {
+      return handler.areColumnsUnique(scan, mq, columns, ignoreNulls);
+    }
+    return scan.getTable().isKey(columns);
   }
 
   public @Nullable Boolean areColumnsUnique(Filter rel, RelMetadataQuery mq,
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 d172f37f35..b5609acf40 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
@@ -26,6 +26,7 @@ import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.TableModify;
+import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rex.RexBuilder;
@@ -85,6 +86,16 @@ public class RelMdDistinctRowCount
     return null;
   }
 
+  public @Nullable Double getDistinctRowCount(TableScan scan, RelMetadataQuery mq,
+      ImmutableBitSet groupKey, RexNode predicate) {
+    final BuiltInMetadata.DistinctRowCount.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.DistinctRowCount.Handler.class);
+    if (handler != null) {
+      return handler.getDistinctRowCount(scan, mq, groupKey, predicate);
+    }
+    return getDistinctRowCount((RelNode) scan, mq, groupKey, predicate);
+  }
+
   public @Nullable Double getDistinctRowCount(Union rel, RelMetadataQuery mq,
       ImmutableBitSet groupKey, @Nullable RexNode predicate) {
     double rowCount = 0.0;
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java
index 5133dbb939..a0fdf630d6 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdDistribution.java
@@ -91,6 +91,11 @@ public class RelMdDistribution
   }
 
   public @Nullable RelDistribution distribution(TableScan scan, RelMetadataQuery mq) {
+    final BuiltInMetadata.Distribution.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.Distribution.Handler.class);
+    if (handler != null) {
+      return handler.distribution(scan, mq);
+    }
     return table(scan.getTable());
   }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExplainVisibility.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExplainVisibility.java
index 1f5d8f5887..a06b2842a1 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExplainVisibility.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExplainVisibility.java
@@ -17,6 +17,7 @@
 package org.apache.calcite.rel.metadata;
 
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.sql.SqlExplainLevel;
 
 import org.checkerframework.checker.nullness.qual.Nullable;
@@ -52,4 +53,15 @@ public class RelMdExplainVisibility
     // no information available
     return null;
   }
+
+  public @Nullable Boolean isVisibleInExplain(TableScan scan, RelMetadataQuery mq,
+      SqlExplainLevel explainLevel) {
+    final BuiltInMetadata.ExplainVisibility.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.ExplainVisibility.Handler.class);
+    if (handler != null) {
+      return handler.isVisibleInExplain(scan, mq, explainLevel);
+    }
+    // Fall back to the catch-all.
+    return isVisibleInExplain((RelNode) scan, mq, explainLevel);
+  }
 }
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExpressionLineage.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExpressionLineage.java
index e21fcb5f31..05fc3e0fe4 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExpressionLineage.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdExpressionLineage.java
@@ -119,6 +119,12 @@ public class RelMdExpressionLineage
    */
   public @Nullable Set<RexNode> getExpressionLineage(TableScan rel,
       RelMetadataQuery mq, RexNode outputExpression) {
+    final BuiltInMetadata.ExpressionLineage.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.ExpressionLineage.Handler.class);
+    if (handler != null) {
+      return handler.getExpressionLineage(rel, mq, outputExpression);
+    }
+
     final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
 
     // Extract input fields referenced by expression
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java
index a3c4b18afe..c8cec39f98 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMaxRowCount.java
@@ -181,7 +181,12 @@ public class RelMdMaxRowCount
     return left * right;
   }
 
-  public Double getMaxRowCount(TableScan rel, RelMetadataQuery mq) {
+  public @Nullable Double getMaxRowCount(TableScan rel, RelMetadataQuery mq) {
+    final BuiltInMetadata.MaxRowCount.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.MaxRowCount.Handler.class);
+    if (handler != null) {
+      return handler.getMaxRowCount(rel, mq);
+    }
     // For typical tables, there is no upper bound to the number of rows.
     return Double.POSITIVE_INFINITY;
   }
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMinRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMinRowCount.java
index 131fec5de2..1d392aad13 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMinRowCount.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdMinRowCount.java
@@ -147,7 +147,12 @@ public class RelMdMinRowCount
     return 0D;
   }
 
-  public Double getMinRowCount(TableScan rel, RelMetadataQuery mq) {
+  public @Nullable Double getMinRowCount(TableScan rel, RelMetadataQuery mq) {
+    final BuiltInMetadata.MinRowCount.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.MinRowCount.Handler.class);
+    if (handler != null) {
+      return handler.getMinRowCount(rel, mq);
+    }
     return 0D;
   }
 
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 a7d160fcf8..60aa05f9f2 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
@@ -125,6 +125,11 @@ public class RelMdNodeTypes
 
   public @Nullable Multimap<Class<? extends RelNode>, RelNode> getNodeTypes(TableScan rel,
       RelMetadataQuery mq) {
+    final BuiltInMetadata.NodeTypes.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.NodeTypes.Handler.class);
+    if (handler != null) {
+      return handler.getNodeTypes(rel, mq);
+    }
     return getNodeTypes(rel, TableScan.class, mq);
   }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdParallelism.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdParallelism.java
index 2bd1747049..ef08fff91b 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdParallelism.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdParallelism.java
@@ -58,6 +58,11 @@ public class RelMdParallelism
   }
 
   public Boolean isPhaseTransition(TableScan rel, RelMetadataQuery mq) {
+    final BuiltInMetadata.Parallelism.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.Parallelism.Handler.class);
+    if (handler != null) {
+      return handler.isPhaseTransition(rel, mq);
+    }
     return true;
   }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPercentageOriginalRows.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPercentageOriginalRows.java
index a25d2eebf2..e69cd5646d 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPercentageOriginalRows.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPercentageOriginalRows.java
@@ -21,6 +21,7 @@ import org.apache.calcite.plan.RelOptCost;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.Join;
+import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.core.Union;
 
 import com.google.common.collect.ImmutableList;
@@ -55,6 +56,15 @@ public class RelMdPercentageOriginalRows {
 
   private RelMdPercentageOriginalRows() {}
 
+  public @Nullable Double getPercentageOriginalRows(TableScan scan, RelMetadataQuery mq) {
+    final BuiltInMetadata.PercentageOriginalRows.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.PercentageOriginalRows.Handler.class);
+    if (handler != null) {
+      return handler.getPercentageOriginalRows(scan, mq);
+    }
+    // Fall back to the catch-all.
+    return getPercentageOriginalRows((RelNode) scan, mq);
+  }
 
   public @Nullable Double getPercentageOriginalRows(Aggregate rel, RelMetadataQuery mq) {
     // REVIEW jvs 28-Mar-2006: The assumption here seems to be that
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 779457fb59..963c3bac5f 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
@@ -24,6 +24,7 @@ import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.TableModify;
+import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rex.RexNode;
@@ -54,6 +55,16 @@ public class RelMdPopulationSize
     return BuiltInMetadata.PopulationSize.DEF;
   }
 
+  public @Nullable Double getPopulationSize(TableScan scan, RelMetadataQuery mq,
+      ImmutableBitSet groupKey) {
+    final BuiltInMetadata.PopulationSize.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.PopulationSize.Handler.class);
+    if (handler != null) {
+      return handler.getPopulationSize(scan, mq, groupKey);
+    }
+    return getPopulationSize((RelNode) scan, mq, groupKey);
+  }
+
   public @Nullable Double getPopulationSize(Filter rel, RelMetadataQuery mq,
       ImmutableBitSet groupKey) {
     return mq.getPopulationSize(rel.getInput(), groupKey);
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
index e194c82703..da71912046 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
@@ -149,8 +149,13 @@ public class RelMdPredicates
   /**
    * Infers predicates for a table scan.
    */
-  public RelOptPredicateList getPredicates(TableScan table,
+  public RelOptPredicateList getPredicates(TableScan scan,
       RelMetadataQuery mq) {
+    final BuiltInMetadata.Predicates.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.Predicates.Handler.class);
+    if (handler != null) {
+      return handler.getPredicates(scan, mq);
+    }
     return RelOptPredicateList.EMPTY;
   }
 
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 5eb8178826..2066c867fe 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
@@ -197,7 +197,12 @@ public class RelMdRowCount
     return distinctRowCount;
   }
 
-  public Double getRowCount(TableScan rel, RelMetadataQuery mq) {
+  public @Nullable Double getRowCount(TableScan rel, RelMetadataQuery mq) {
+    final BuiltInMetadata.RowCount.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.RowCount.Handler.class);
+    if (handler != null) {
+      return handler.getRowCount(rel, mq);
+    }
     return rel.estimateRowCount(mq);
   }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
index f61b26cf88..709b8d11c7 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
@@ -25,6 +25,7 @@ import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.TableModify;
+import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexLocalRef;
@@ -60,6 +61,16 @@ public class RelMdSelectivity
     return BuiltInMetadata.Selectivity.DEF;
   }
 
+  public @Nullable Double getSelectivity(TableScan scan, RelMetadataQuery mq,
+      RexNode predicate) {
+    final BuiltInMetadata.Selectivity.Handler handler =
+        scan.getTable().unwrap(BuiltInMetadata.Selectivity.Handler.class);
+    if (handler != null) {
+      return handler.getSelectivity(scan, mq, predicate);
+    }
+    return getSelectivity((RelNode) scan, mq, predicate);
+  }
+
   public @Nullable Double getSelectivity(Union rel, RelMetadataQuery mq,
       @Nullable RexNode predicate) {
     if ((rel.getInputs().size() == 0) || (predicate == null)) {
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 77b2ed6fd7..ca91d51478 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
@@ -171,7 +171,12 @@ public class RelMdSize implements MetadataHandler<BuiltInMetadata.Size> {
     return list.build();
   }
 
-  public List<@Nullable Double> averageColumnSizes(TableScan rel, RelMetadataQuery mq) {
+  public @Nullable List<@Nullable Double> averageColumnSizes(TableScan rel, RelMetadataQuery mq) {
+    final BuiltInMetadata.Size.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.Size.Handler.class);
+    if (handler != null) {
+      return handler.averageColumnSizes(rel, mq);
+    }
     final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
     final ImmutableNullableList.Builder<@Nullable Double> list = ImmutableNullableList.builder();
     for (RelDataTypeField field : fields) {
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdTableReferences.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdTableReferences.java
index e9554a6946..4c78ab1b6c 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdTableReferences.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdTableReferences.java
@@ -92,6 +92,11 @@ public class RelMdTableReferences
    * TableScan table reference.
    */
   public Set<RelTableRef> getTableReferences(TableScan rel, RelMetadataQuery mq) {
+    final BuiltInMetadata.TableReferences.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.TableReferences.Handler.class);
+    if (handler != null) {
+      return handler.getTableReferences(rel, mq);
+    }
     return ImmutableSet.of(RelTableRef.of(rel.getTable(), 0));
   }
 
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 21bfdbed29..13374cc208 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
@@ -322,6 +322,12 @@ public class RelMdUniqueKeys
 
   public @Nullable Set<ImmutableBitSet> getUniqueKeys(TableScan rel, RelMetadataQuery mq,
       boolean ignoreNulls) {
+    final BuiltInMetadata.UniqueKeys.Handler handler =
+        rel.getTable().unwrap(BuiltInMetadata.UniqueKeys.Handler.class);
+    if (handler != null) {
+      return handler.getUniqueKeys(rel, mq, ignoreNulls);
+    }
+
     final List<ImmutableBitSet> keys = rel.getTable().getKeys();
     if (keys == null) {
       return null;
diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
index d7ec865c70..ee73bcab6b 100644
--- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java
@@ -3261,6 +3261,44 @@ public class RelMetadataTest {
     });
   }
 
+  /** Unit test for
+   * {@link org.apache.calcite.rel.metadata.RelMetadataQuery#getAverageColumnSizes(org.apache.calcite.rel.RelNode)}
+   * with a table that has its own implementation of {@link BuiltInMetadata.Size}. */
+  @Test void testCustomizedAverageColumnSizes() {
+    SqlTestFactory.CatalogReaderFactory factory = (typeFactory, caseSensitive) -> {
+      CompositeKeysCatalogReader catalogReader =
+          new CompositeKeysCatalogReader(typeFactory, false);
+      catalogReader.init();
+      return catalogReader;
+    };
+
+    final RelNode rel = sql("select key1, key2 from s.composite_keys_table")
+        .withCatalogReaderFactory(factory).toRel();
+    final RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
+    List<Double> columnSizes = mq.getAverageColumnSizes(rel);
+    assertThat(columnSizes.size(), is(2));
+    assertThat(columnSizes.get(0), is(2.0));
+    assertThat(columnSizes.get(1), is(3.0));
+  }
+
+  /** Unit test for
+   * {@link org.apache.calcite.rel.metadata.RelMetadataQuery#getDistinctRowCount(RelNode, ImmutableBitSet, RexNode)}
+   * with a table that has its own implementation of {@link BuiltInMetadata.Size}. */
+  @Test void testCustomizedDistinctRowcount() {
+    SqlTestFactory.CatalogReaderFactory factory = (typeFactory, caseSensitive) -> {
+      CompositeKeysCatalogReader catalogReader =
+          new CompositeKeysCatalogReader(typeFactory, false);
+      catalogReader.init();
+      return catalogReader;
+    };
+
+    final RelNode rel = sql("select key1, key2 from s.composite_keys_table")
+        .withCatalogReaderFactory(factory).toRel();
+    final RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
+    Double ndv = mq.getDistinctRowCount(rel, ImmutableBitSet.of(0, 1), null);
+    assertThat(ndv, is(100.0));
+  }
+
   private void checkInputForCollationAndLimit(RelOptCluster cluster, RelOptTable empTable,
       RelOptTable deptTable) {
     final RexBuilder rexBuilder = cluster.getRexBuilder();
@@ -3404,8 +3442,48 @@ public class RelMetadataTest {
       t1.addColumn("key1", typeFactory.createSqlType(SqlTypeName.VARCHAR), true);
       t1.addColumn("key2", typeFactory.createSqlType(SqlTypeName.VARCHAR), true);
       t1.addColumn("value1", typeFactory.createSqlType(SqlTypeName.INTEGER));
+      addSizeHandler(t1);
+      addDistinctRowcountHandler(t1);
+      addUniqueKeyHandler(t1);
       registerTable(t1);
       return this;
     }
+
+    private void addSizeHandler(MockTable table) {
+      table.addWrap(
+          new BuiltInMetadata.Size.Handler() {
+            @Override public @Nullable Double averageRowSize(RelNode r, RelMetadataQuery mq) {
+              return null;
+            }
+
+            @Override public @Nullable List<@Nullable Double> averageColumnSizes(RelNode r,
+                RelMetadataQuery mq) {
+              List<Double> colSize = new ArrayList<>();
+              colSize.add(2D);
+              colSize.add(3D);
+              return colSize;
+            }
+          });
+    }
+
+    private void addDistinctRowcountHandler(MockTable table) {
+      table.addWrap(
+          new BuiltInMetadata.DistinctRowCount.Handler() {
+            @Override public @Nullable Double getDistinctRowCount(RelNode r, RelMetadataQuery mq,
+                ImmutableBitSet groupKey, @Nullable RexNode predicate) {
+              return 100D;
+            }
+          });
+    }
+
+    private void addUniqueKeyHandler(MockTable table) {
+      table.addWrap(
+          new BuiltInMetadata.UniqueKeys.Handler() {
+            @Override public @Nullable Set<ImmutableBitSet> getUniqueKeys(RelNode r,
+                RelMetadataQuery mq, boolean ignoreNulls) {
+              return ImmutableSet.of(ImmutableBitSet.of(0, 1));
+            }
+          });
+    }
   }
 }
diff --git a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_ColumnOriginHandler.java b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_ColumnOriginHandler.java
index d689d4a115..6063a0e006 100644
--- a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_ColumnOriginHandler.java
+++ b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_ColumnOriginHandler.java
@@ -90,6 +90,8 @@ public final class GeneratedMetadata_ColumnOriginHandler
       return provider0.getColumnOrigins((org.apache.calcite.rel.core.TableFunctionScan) r, mq, a2);
     } else if (r instanceof org.apache.calcite.rel.core.TableModify) {
       return provider0.getColumnOrigins((org.apache.calcite.rel.core.TableModify) r, mq, a2);
+    } else if (r instanceof org.apache.calcite.rel.core.TableScan) {
+      return provider0.getColumnOrigins((org.apache.calcite.rel.core.TableScan) r, mq, a2);
     } else if (r instanceof org.apache.calcite.rel.RelNode) {
       return provider0.getColumnOrigins((org.apache.calcite.rel.RelNode) r, mq, a2);
     } else {
diff --git a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_DistinctRowCountHandler.java b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_DistinctRowCountHandler.java
index 52bd502e3e..52ad30b842 100644
--- a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_DistinctRowCountHandler.java
+++ b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_DistinctRowCountHandler.java
@@ -80,6 +80,8 @@ public final class GeneratedMetadata_DistinctRowCountHandler
       return provider0.getDistinctRowCount((org.apache.calcite.rel.core.Sort) r, mq, a2, a3);
     } else if (r instanceof org.apache.calcite.rel.core.TableModify) {
       return provider0.getDistinctRowCount((org.apache.calcite.rel.core.TableModify) r, mq, a2, a3);
+    } else if (r instanceof org.apache.calcite.rel.core.TableScan) {
+      return provider0.getDistinctRowCount((org.apache.calcite.rel.core.TableScan) r, mq, a2, a3);
     } else if (r instanceof org.apache.calcite.rel.core.Union) {
       return provider0.getDistinctRowCount((org.apache.calcite.rel.core.Union) r, mq, a2, a3);
     } else if (r instanceof org.apache.calcite.rel.core.Values) {
diff --git a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_ExplainVisibilityHandler.java b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_ExplainVisibilityHandler.java
index 62d898c2f3..fb3ec846fb 100644
--- a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_ExplainVisibilityHandler.java
+++ b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_ExplainVisibilityHandler.java
@@ -68,7 +68,9 @@ public final class GeneratedMetadata_ExplainVisibilityHandler
       org.apache.calcite.rel.RelNode r,
       org.apache.calcite.rel.metadata.RelMetadataQuery mq,
       org.apache.calcite.sql.SqlExplainLevel a2) {
-    if (r instanceof org.apache.calcite.rel.RelNode) {
+    if (r instanceof org.apache.calcite.rel.core.TableScan) {
+      return provider0.isVisibleInExplain((org.apache.calcite.rel.core.TableScan) r, mq, a2);
+    } else if (r instanceof org.apache.calcite.rel.RelNode) {
       return provider0.isVisibleInExplain((org.apache.calcite.rel.RelNode) r, mq, a2);
     } else {
             throw new java.lang.IllegalArgumentException("No handler for method [public abstract java.lang.Boolean org.apache.calcite.rel.metadata.BuiltInMetadata$ExplainVisibility$Handler.isVisibleInExplain(org.apache.calcite.rel.RelNode,org.apache.calcite.rel.metadata.RelMetadataQuery,org.apache.calcite.sql.SqlExplainLevel)] applied to argument of type [" + r.getClass() + "]; we recommend you create a catch-all (RelNode) handler");
diff --git a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_PercentageOriginalRowsHandler.java b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_PercentageOriginalRowsHandler.java
index 573ceb39e7..d83e952a92 100644
--- a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_PercentageOriginalRowsHandler.java
+++ b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_PercentageOriginalRowsHandler.java
@@ -64,6 +64,8 @@ public final class GeneratedMetadata_PercentageOriginalRowsHandler
       return provider0.getPercentageOriginalRows((org.apache.calcite.rel.core.Aggregate) r, mq);
     } else if (r instanceof org.apache.calcite.rel.core.Join) {
       return provider0.getPercentageOriginalRows((org.apache.calcite.rel.core.Join) r, mq);
+    } else if (r instanceof org.apache.calcite.rel.core.TableScan) {
+      return provider0.getPercentageOriginalRows((org.apache.calcite.rel.core.TableScan) r, mq);
     } else if (r instanceof org.apache.calcite.rel.core.Union) {
       return provider0.getPercentageOriginalRows((org.apache.calcite.rel.core.Union) r, mq);
     } else if (r instanceof org.apache.calcite.rel.RelNode) {
diff --git a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_PopulationSizeHandler.java b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_PopulationSizeHandler.java
index 944a4eb7f3..188fd5aa4d 100644
--- a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_PopulationSizeHandler.java
+++ b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_PopulationSizeHandler.java
@@ -76,6 +76,8 @@ public final class GeneratedMetadata_PopulationSizeHandler
       return provider0.getPopulationSize((org.apache.calcite.rel.core.Sort) r, mq, a2);
     } else if (r instanceof org.apache.calcite.rel.core.TableModify) {
       return provider0.getPopulationSize((org.apache.calcite.rel.core.TableModify) r, mq, a2);
+    } else if (r instanceof org.apache.calcite.rel.core.TableScan) {
+      return provider0.getPopulationSize((org.apache.calcite.rel.core.TableScan) r, mq, a2);
     } else if (r instanceof org.apache.calcite.rel.core.Union) {
       return provider0.getPopulationSize((org.apache.calcite.rel.core.Union) r, mq, a2);
     } else if (r instanceof org.apache.calcite.rel.core.Values) {
diff --git a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_SelectivityHandler.java b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_SelectivityHandler.java
index 4eed8d7071..7010ada5d3 100644
--- a/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_SelectivityHandler.java
+++ b/core/src/test/resources/org/apache/calcite/rel/metadata/janino/GeneratedMetadata_SelectivityHandler.java
@@ -76,6 +76,8 @@ public final class GeneratedMetadata_SelectivityHandler
       return provider0.getSelectivity((org.apache.calcite.rel.core.Sort) r, mq, a2);
     } else if (r instanceof org.apache.calcite.rel.core.TableModify) {
       return provider0.getSelectivity((org.apache.calcite.rel.core.TableModify) r, mq, a2);
+    } else if (r instanceof org.apache.calcite.rel.core.TableScan) {
+      return provider0.getSelectivity((org.apache.calcite.rel.core.TableScan) r, mq, a2);
     } else if (r instanceof org.apache.calcite.rel.core.Union) {
       return provider0.getSelectivity((org.apache.calcite.rel.core.Union) r, mq, a2);
     } else if (r instanceof org.apache.calcite.rel.RelNode) {
diff --git a/testkit/src/main/java/org/apache/calcite/test/catalog/MockCatalogReader.java b/testkit/src/main/java/org/apache/calcite/test/catalog/MockCatalogReader.java
index edffe58ec8..8cc3539697 100644
--- a/testkit/src/main/java/org/apache/calcite/test/catalog/MockCatalogReader.java
+++ b/testkit/src/main/java/org/apache/calcite/test/catalog/MockCatalogReader.java
@@ -366,7 +366,7 @@ public abstract class MockCatalogReader extends CalciteCatalogReader {
       this.wraps = ImmutableList.of();
     }
 
-    void addWrap(Object wrap) {
+    public void addWrap(Object wrap) {
       if (wraps instanceof ImmutableList) {
         wraps = new ArrayList<>(wraps);
       }