blob: a99a6dc441dd42fdc0e957ca02208146b55fa6bb [file] [log] [blame]
/*
* 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.calcite.plan.volcano;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.metadata.Metadata;
import org.apache.calcite.rel.metadata.MetadataDef;
import org.apache.calcite.rel.metadata.MetadataHandler;
import org.apache.calcite.rel.metadata.RelMetadataProvider;
import org.apache.calcite.rel.metadata.UnboundMetadata;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* VolcanoRelMetadataProvider implements the {@link RelMetadataProvider}
* interface by combining metadata from the rels making up an equivalence class.
*/
@Deprecated // to be removed before 2.0
public class VolcanoRelMetadataProvider implements RelMetadataProvider {
//~ Methods ----------------------------------------------------------------
@Override public boolean equals(@Nullable Object obj) {
return obj instanceof VolcanoRelMetadataProvider;
}
@Override public int hashCode() {
return 103;
}
@Deprecated // to be removed before 2.0
@Override public <@Nullable M extends @Nullable Metadata> @Nullable UnboundMetadata<M> apply(
Class<? extends RelNode> relClass,
final Class<? extends M> metadataClass) {
if (relClass != RelSubset.class) {
// let someone else further down the chain sort it out
return null;
}
return (rel, mq) -> {
final RelSubset subset = (RelSubset) rel;
final RelMetadataProvider provider = Objects.requireNonNull(
rel.getCluster().getMetadataProvider(),
"metadataProvider");
// REVIEW jvs 29-Mar-2006: I'm not sure what the correct precedence
// should be here. Letting the current best plan take the first shot is
// probably the right thing to do for physical estimates such as row
// count. Dunno about others, and whether we need a way to
// discriminate.
// First, try current best implementation. If it knows how to answer
// this query, treat it as the most reliable.
if (subset.best != null) {
RelNode best = subset.best;
final UnboundMetadata<M> function =
provider.apply(best.getClass(), metadataClass);
if (function != null) {
final M metadata = function.bind(best, mq);
if (metadata != null) {
return metadata;
}
}
}
// Otherwise, try rels in same logical equivalence class to see if any
// of them have a good answer. We use the full logical equivalence
// class rather than just the subset because many metadata providers
// only know about logical metadata.
// Equivalence classes can get tangled up in interesting ways, so avoid
// an infinite loop. REVIEW: There's a chance this will cause us to
// fail on metadata queries which invoke other queries, e.g.
// PercentageOriginalRows -> Selectivity. If we implement caching at
// this level, we could probably kill two birds with one stone (use
// presence of pending cache entry to detect re-entrancy at the correct
// granularity).
if (subset.set.inMetadataQuery) {
return null;
}
subset.set.inMetadataQuery = true;
try {
for (RelNode relCandidate : subset.set.rels) {
final UnboundMetadata<M> function =
provider.apply(relCandidate.getClass(), metadataClass);
if (function != null) {
final M result = function.bind(relCandidate, mq);
if (result != null) {
return result;
}
}
}
} finally {
subset.set.inMetadataQuery = false;
}
// Give up.
return null;
};
}
@Override public <M extends Metadata> Multimap<Method, MetadataHandler<M>> handlers(
MetadataDef<M> def) {
return ImmutableMultimap.of();
}
}