You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by da...@apache.org on 2019/10/08 03:48:42 UTC
[calcite] 01/01: [CALCITE-2018] Queries failed with AssertionError:
rel has lower cost than best cost of subset
This is an automated email from the ASF dual-hosted git repository.
danny0405 pushed a commit to branch vvysotskyi-CALCITE-2018
in repository https://gitbox.apache.org/repos/asf/calcite.git
commit 4ffb668e98376f294a677b1bb7fb2709b042e02a
Author: Volodymyr Vysotskyi <vv...@gmail.com>
AuthorDate: Tue Dec 19 14:57:27 2017 +0200
[CALCITE-2018] Queries failed with AssertionError: rel has lower cost than best cost of subset
---
.../calcite/adapter/enumerable/EnumerableCalc.java | 2 +-
.../apache/calcite/plan/AbstractRelOptPlanner.java | 2 +-
.../org/apache/calcite/plan/hep/HepPlanner.java | 5 +++-
.../org/apache/calcite/plan/volcano/RelSet.java | 23 ++++++++++++++----
.../org/apache/calcite/plan/volcano/RelSubset.java | 8 ++++++-
.../calcite/plan/volcano/VolcanoPlanner.java | 2 ++
.../calcite/prepare/CalciteMaterializer.java | 8 +++----
.../apache/calcite/prepare/CalcitePrepareImpl.java | 27 +++++++++++-----------
.../org/apache/calcite/rel/AbstractRelNode.java | 8 +++----
.../java/org/apache/calcite/rel/core/Filter.java | 4 ++--
.../java/org/apache/calcite/rel/core/Join.java | 2 +-
.../java/org/apache/calcite/rel/core/Union.java | 2 +-
.../rel/metadata/JaninoRelMetadataProvider.java | 9 ++++----
.../metadata/ReflectiveRelMetadataProvider.java | 4 ++--
.../org/apache/calcite/rel/metadata/RelMdUtil.java | 9 ++++++++
.../calcite/rel/metadata/RelMetadataQuery.java | 15 +++++++++---
16 files changed, 87 insertions(+), 43 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
index 54eec73..6d01710 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableCalc.java
@@ -143,7 +143,7 @@ public class EnumerableCalc extends Calc implements EnumerableRel {
inputJavaType);
final RexBuilder rexBuilder = getCluster().getRexBuilder();
- final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final RelMetadataQuery mq = getCluster().getMetadataQuery();
final RelOptPredicateList predicates = mq.getPulledUpPredicates(child);
final RexSimplify simplify =
new RexSimplify(rexBuilder, predicates, RexUtil.EXECUTOR);
diff --git a/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java b/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java
index 48af98d..93c16f2 100644
--- a/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/AbstractRelOptPlanner.java
@@ -248,7 +248,7 @@ public abstract class AbstractRelOptPlanner implements RelOptPlanner {
@SuppressWarnings("deprecation")
public RelOptCost getCost(RelNode rel) {
- final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
return getCost(rel, mq);
}
diff --git a/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java b/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java
index 9ae96f8..d6ba1a0 100644
--- a/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/hep/HepPlanner.java
@@ -35,6 +35,7 @@ import org.apache.calcite.rel.convert.Converter;
import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.convert.TraitMatchingRule;
import org.apache.calcite.rel.core.RelFactories;
+import org.apache.calcite.rel.metadata.RelMdUtil;
import org.apache.calcite.rel.metadata.RelMetadataProvider;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
@@ -867,6 +868,7 @@ public class HepPlanner extends AbstractRelOptPlanner {
}
parentRel.replaceInput(i, preservedVertex);
}
+ RelMdUtil.clearCache(parentRel);
graph.removeEdge(parent, discardedVertex);
graph.addEdge(parent, preservedVertex);
updateVertex(parent, parentRel);
@@ -932,8 +934,9 @@ public class HepPlanner extends AbstractRelOptPlanner {
}
child = buildFinalPlan((HepRelVertex) child);
rel.replaceInput(i, child);
- rel.recomputeDigest();
}
+ RelMdUtil.clearCache(rel);
+ rel.recomputeDigest();
return rel;
}
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
index 5d17fde..f866068 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSet.java
@@ -33,7 +33,9 @@ import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.IdentityHashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/**
@@ -311,11 +313,14 @@ class RelSet {
assert otherSet.equivalentSet == null;
LOGGER.trace("Merge set#{} into set#{}", otherSet.id, id);
otherSet.equivalentSet = this;
+ RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
// remove from table
boolean existed = planner.allSets.remove(otherSet);
assert existed : "merging with a dead otherSet";
+ Map<RelSubset, RelNode> changedSubsets = new IdentityHashMap<>();
+
// merge subsets
for (RelSubset otherSubset : otherSet.subsets) {
planner.ruleQueue.subsetImportances.remove(otherSubset);
@@ -323,9 +328,9 @@ class RelSet {
getOrCreateSubset(
otherSubset.getCluster(),
otherSubset.getTraitSet());
+ // collect RelSubset instances, whose best should be changed
if (otherSubset.bestCost.isLt(subset.bestCost)) {
- subset.bestCost = otherSubset.bestCost;
- subset.best = otherSubset.best;
+ changedSubsets.put(subset, otherSubset.best);
}
for (RelNode otherRel : otherSubset.getRels()) {
planner.reregister(this, otherRel);
@@ -335,6 +340,18 @@ class RelSet {
// Has another set merged with this?
assert equivalentSet == null;
+ // calls propagateCostImprovements() for RelSubset instances,
+ // whose best should be changed to check whether that
+ // subset's parents get cheaper.
+ Set<RelSubset> activeSet = new HashSet<>();
+ for (Map.Entry<RelSubset, RelNode> subsetBestPair : changedSubsets.entrySet()) {
+ RelSubset relSubset = subsetBestPair.getKey();
+ relSubset.propagateCostImprovements(
+ planner, mq, subsetBestPair.getValue(),
+ activeSet);
+ }
+ assert activeSet.isEmpty();
+
// Update all rels which have a child in the other set, to reflect the
// fact that the child has been renamed.
//
@@ -353,8 +370,6 @@ class RelSet {
}
// Make sure the cost changes as a result of merging are propagated.
- final Set<RelSubset> activeSet = new HashSet<>();
- final RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
for (RelNode parentRel : getParentRels()) {
final RelSubset parentSubset = planner.getSubset(parentRel);
parentSubset.propagateCostImprovements(
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java
index 7c78f71..207eb9b 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/RelSubset.java
@@ -208,7 +208,8 @@ public class RelSubset extends AbstractRelNode {
final Set<RelNode> list = new LinkedHashSet<>();
for (RelNode parent : set.getParentRels()) {
for (RelSubset rel : inputSubsets(parent)) {
- if (rel.set == set && traitSet.satisfies(rel.getTraitSet())) {
+ // see usage of this method in propagateCostImprovements0()
+ if (rel == this) {
list.add(parent);
}
}
@@ -367,11 +368,16 @@ public class RelSubset extends AbstractRelNode {
bestCost = cost;
best = rel;
+ // since best was changed, cached metadata for this subset should be removed
+ mq.clearCache(this);
// Recompute subset's importance and propagate cost change to parents
planner.ruleQueue.recompute(this);
for (RelNode parent : getParents()) {
+ // removes parent cached metadata since its input was changed
+ mq.clearCache(parent);
final RelSubset parentSubset = planner.getSubset(parent);
+ // parent subset will clear its cache in propagateCostImprovements0 method itself
parentSubset.propagateCostImprovements(planner, mq, parent,
activeSet);
}
diff --git a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
index 4f96637..5644ea0 100644
--- a/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
+++ b/core/src/main/java/org/apache/calcite/plan/volcano/VolcanoPlanner.java
@@ -46,6 +46,7 @@ import org.apache.calcite.rel.convert.Converter;
import org.apache.calcite.rel.convert.ConverterRule;
import org.apache.calcite.rel.externalize.RelWriterImpl;
import org.apache.calcite.rel.metadata.JaninoRelMetadataProvider;
+import org.apache.calcite.rel.metadata.RelMdUtil;
import org.apache.calcite.rel.metadata.RelMetadataProvider;
import org.apache.calcite.rel.metadata.RelMetadataQuery;
import org.apache.calcite.rel.type.RelDataType;
@@ -1566,6 +1567,7 @@ public class VolcanoPlanner extends AbstractRelOptPlanner {
}
}
}
+ RelMdUtil.clearCache(rel);
return changeCount > 0;
}
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
index 65fef8d..a977954 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalciteMaterializer.java
@@ -21,8 +21,8 @@ import org.apache.calcite.config.CalciteSystemProperty;
import org.apache.calcite.interpreter.BindableConvention;
import org.apache.calcite.jdbc.CalcitePrepare;
import org.apache.calcite.jdbc.CalciteSchema;
+import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptMaterialization;
-import org.apache.calcite.plan.RelOptPlanner;
import org.apache.calcite.plan.RelOptTable;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
@@ -63,10 +63,10 @@ class CalciteMaterializer extends CalcitePrepareImpl.CalcitePreparingStmt {
CalciteMaterializer(CalcitePrepareImpl prepare,
CalcitePrepare.Context context,
CatalogReader catalogReader, CalciteSchema schema,
- RelOptPlanner planner, SqlRexConvertletTable convertletTable) {
+ SqlRexConvertletTable convertletTable, RelOptCluster cluster) {
super(prepare, context, catalogReader, catalogReader.getTypeFactory(),
- schema, EnumerableRel.Prefer.ANY, planner, BindableConvention.INSTANCE,
- convertletTable);
+ schema, EnumerableRel.Prefer.ANY, BindableConvention.INSTANCE,
+ convertletTable, cluster);
}
/** Populates a materialization record, converting a table path
diff --git a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
index 7faead7..8eb98e5 100644
--- a/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/CalcitePrepareImpl.java
@@ -225,8 +225,8 @@ public class CalcitePrepareImpl implements CalcitePrepare {
final CalcitePreparingStmt preparingStmt =
new CalcitePreparingStmt(this, context, catalogReader, typeFactory,
- context.getRootSchema(), null, planner, resultConvention,
- createConvertletTable());
+ context.getRootSchema(), null, resultConvention, createConvertletTable(),
+ createCluster(planner, new RexBuilder(typeFactory)));
final SqlToRelConverter converter =
preparingStmt.getSqlToRelConverter(validator, catalogReader,
configBuilder.build());
@@ -588,8 +588,8 @@ public class CalcitePrepareImpl implements CalcitePrepare {
: EnumerableConvention.INSTANCE;
final CalcitePreparingStmt preparingStmt =
new CalcitePreparingStmt(this, context, catalogReader, typeFactory,
- context.getRootSchema(), prefer, planner, resultConvention,
- createConvertletTable());
+ context.getRootSchema(), prefer, resultConvention, createConvertletTable(),
+ createCluster(planner, new RexBuilder(typeFactory)));
final RelDataType x;
final Prepare.PreparedResult preparedResult;
@@ -855,7 +855,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
}
protected void populateMaterializations(Context context,
- RelOptPlanner planner, Prepare.Materialization materialization) {
+ Prepare.Materialization materialization, RelOptCluster cluster) {
// REVIEW: initialize queryRel and tableRel inside MaterializationService,
// not here?
try {
@@ -867,8 +867,8 @@ public class CalcitePrepareImpl implements CalcitePrepare {
context.getTypeFactory(),
context.config());
final CalciteMaterializer materializer =
- new CalciteMaterializer(this, context, catalogReader, schema, planner,
- createConvertletTable());
+ new CalciteMaterializer(this, context, catalogReader, schema,
+ createConvertletTable(), cluster);
materializer.populate(materialization);
} catch (Exception e) {
throw new RuntimeException("While populating materialization "
@@ -926,6 +926,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
protected final RelDataTypeFactory typeFactory;
protected final SqlRexConvertletTable convertletTable;
private final EnumerableRel.Prefer prefer;
+ private final RelOptCluster cluster;
private final Map<String, Object> internalParameters =
new LinkedHashMap<>();
private int expansionDepth;
@@ -937,17 +938,18 @@ public class CalcitePrepareImpl implements CalcitePrepare {
RelDataTypeFactory typeFactory,
CalciteSchema schema,
EnumerableRel.Prefer prefer,
- RelOptPlanner planner,
Convention resultConvention,
- SqlRexConvertletTable convertletTable) {
+ SqlRexConvertletTable convertletTable,
+ RelOptCluster cluster) {
super(context, catalogReader, resultConvention);
this.prepare = prepare;
this.schema = schema;
this.prefer = prefer;
- this.planner = planner;
+ this.cluster = cluster;
+ this.planner = cluster.getPlanner();
+ this.rexBuilder = cluster.getRexBuilder();
this.typeFactory = typeFactory;
this.convertletTable = convertletTable;
- this.rexBuilder = new RexBuilder(typeFactory);
}
@Override protected void init(Class runtimeContextClass) {
@@ -1016,7 +1018,6 @@ public class CalcitePrepareImpl implements CalcitePrepare {
SqlValidator validator,
CatalogReader catalogReader,
SqlToRelConverter.Config config) {
- final RelOptCluster cluster = prepare.createCluster(planner, rexBuilder);
return new SqlToRelConverter(this, validator, catalogReader, cluster,
convertletTable, config);
}
@@ -1152,7 +1153,7 @@ public class CalcitePrepareImpl implements CalcitePrepare {
? MaterializationService.instance().query(schema)
: ImmutableList.of();
for (Prepare.Materialization materialization : materializations) {
- prepare.populateMaterializations(context, planner, materialization);
+ prepare.populateMaterializations(context, materialization, cluster);
}
return materializations;
}
diff --git a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
index d957ea2..20f264f 100644
--- a/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
+++ b/core/src/main/java/org/apache/calcite/rel/AbstractRelNode.java
@@ -158,13 +158,13 @@ public abstract class AbstractRelNode implements RelNode {
@SuppressWarnings("deprecation")
public boolean isDistinct() {
- final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final RelMetadataQuery mq = cluster.getMetadataQuery();
return Boolean.TRUE.equals(mq.areRowsUnique(this));
}
@SuppressWarnings("deprecation")
public boolean isKey(ImmutableBitSet columns) {
- final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final RelMetadataQuery mq = cluster.getMetadataQuery();
return Boolean.TRUE.equals(mq.areColumnsUnique(this, columns));
}
@@ -236,7 +236,7 @@ public abstract class AbstractRelNode implements RelNode {
@SuppressWarnings("deprecation")
public final double getRows() {
- return estimateRowCount(RelMetadataQuery.instance());
+ return estimateRowCount(cluster.getMetadataQuery());
}
public double estimateRowCount(RelMetadataQuery mq) {
@@ -278,7 +278,7 @@ public abstract class AbstractRelNode implements RelNode {
@SuppressWarnings("deprecation")
public final RelOptCost computeSelfCost(RelOptPlanner planner) {
- return computeSelfCost(planner, RelMetadataQuery.instance());
+ return computeSelfCost(planner, cluster.getMetadataQuery());
}
public RelOptCost computeSelfCost(RelOptPlanner planner,
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Filter.java b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
index b539d09..c3c023e 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Filter.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Filter.java
@@ -138,13 +138,13 @@ public abstract class Filter extends SingleRel {
@Deprecated // to be removed before 2.0
public static double estimateFilteredRows(RelNode child, RexProgram program) {
- final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final RelMetadataQuery mq = child.getCluster().getMetadataQuery();
return RelMdUtil.estimateFilteredRows(child, program, mq);
}
@Deprecated // to be removed before 2.0
public static double estimateFilteredRows(RelNode child, RexNode condition) {
- final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final RelMetadataQuery mq = child.getCluster().getMetadataQuery();
return RelMdUtil.estimateFilteredRows(child, condition, mq);
}
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Join.java b/core/src/main/java/org/apache/calcite/rel/core/Join.java
index f201a8d..57339d9 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Join.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Join.java
@@ -196,7 +196,7 @@ public abstract class Join extends BiRel {
public static double estimateJoinedRows(
Join joinRel,
RexNode condition) {
- final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final RelMetadataQuery mq = joinRel.getCluster().getMetadataQuery();
return Util.first(RelMdUtil.getJoinRowCount(mq, joinRel, condition), 1D);
}
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Union.java b/core/src/main/java/org/apache/calcite/rel/core/Union.java
index 942df4a..7bc755a 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Union.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Union.java
@@ -62,7 +62,7 @@ public abstract class Union extends SetOp {
@Deprecated // to be removed before 2.0
public static double estimateRowCount(RelNode rel) {
- final RelMetadataQuery mq = RelMetadataQuery.instance();
+ final RelMetadataQuery mq = rel.getCluster().getMetadataQuery();
return RelMdUtil.getUnionAllRowCount(mq, (Union) rel);
}
}
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java
index 24054bb..dde70fc 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/JaninoRelMetadataProvider.java
@@ -265,10 +265,9 @@ public class JaninoRelMetadataProvider implements RelMetadataProvider {
.append(method.i)
.append(")");
}
- buff.append(", r");
safeArgList(buff, method.e)
.append(");\n")
- .append(" final Object v = mq.map.get(key);\n")
+ .append(" final Object v = mq.map.get(r, key);\n")
.append(" if (v != null) {\n")
.append(" if (v == ")
.append(NullSentinel.class.getName())
@@ -286,7 +285,7 @@ public class JaninoRelMetadataProvider implements RelMetadataProvider {
.append(method.e.getReturnType().getName())
.append(") v;\n")
.append(" }\n")
- .append(" mq.map.put(key,")
+ .append(" mq.map.put(r, key,")
.append(NullSentinel.class.getName())
.append(".ACTIVE);\n")
.append(" try {\n")
@@ -297,14 +296,14 @@ public class JaninoRelMetadataProvider implements RelMetadataProvider {
.append("_(r, mq");
argList(buff, method.e)
.append(");\n")
- .append(" mq.map.put(key, ")
+ .append(" mq.map.put(r, key, ")
.append(NullSentinel.class.getName())
.append(".mask(x));\n")
.append(" return x;\n")
.append(" } catch (")
.append(Exception.class.getName())
.append(" e) {\n")
- .append(" mq.map.remove(key);\n")
+ .append(" mq.map.row(r).clear();\n")
.append(" throw e;\n")
.append(" }\n")
.append(" }\n")
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java b/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
index 20185b7..e164e48 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/ReflectiveRelMetadataProvider.java
@@ -178,7 +178,7 @@ public class ReflectiveRelMetadataProvider
}
key1 = FlatLists.copyOf(args2);
}
- if (mq.map.put(key1, NullSentinel.INSTANCE) != null) {
+ if (mq.map.put(rel, key1, NullSentinel.INSTANCE) != null) {
throw CyclicMetadataException.INSTANCE;
}
try {
@@ -188,7 +188,7 @@ public class ReflectiveRelMetadataProvider
Util.throwIfUnchecked(e.getCause());
throw new RuntimeException(e.getCause());
} finally {
- mq.map.remove(key1);
+ mq.map.remove(rel, key1);
}
});
methodsMap.put(key, function);
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 b53bd9a..dba5a35 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
@@ -874,6 +874,15 @@ public class RelMdUtil {
}
return alreadySorted && alreadySmaller;
}
+
+ /**
+ * Removes cached metadata values for specified RelNode.
+ *
+ * @param rel RelNode whose cached metadata should be removed
+ */
+ public static void clearCache(RelNode rel) {
+ rel.getCluster().getMetadataQuery().clearCache(rel);
+ }
}
// End RelMdUtil.java
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
index e1c37e6..5b7f37d 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
@@ -27,15 +27,15 @@ import org.apache.calcite.rex.RexTableInputRef.RelTableRef;
import org.apache.calcite.sql.SqlExplainLevel;
import org.apache.calcite.util.ImmutableBitSet;
+import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
+import com.google.common.collect.Table;
import java.lang.reflect.Proxy;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -76,7 +76,7 @@ import java.util.Set;
*/
public class RelMetadataQuery {
/** Set of active metadata queries, and cache of previous results. */
- public final Map<List, Object> map = new HashMap<>();
+ public final Table<RelNode, List, Object> map = HashBasedTable.create();
public final JaninoRelMetadataProvider metadataProvider;
@@ -841,6 +841,15 @@ public class RelMetadataQuery {
}
}
+ /**
+ * Removes cached metadata values for specified RelNode.
+ *
+ * @param rel RelNode whose cached metadata should be removed
+ */
+ public void clearCache(RelNode rel) {
+ map.row(rel).clear();
+ }
+
private static Double validatePercentage(Double result) {
assert isPercentage(result, true);
return result;