blob: 779457fb5962dc69d4951131c0d497fb6c39f763 [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.rel.metadata;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Aggregate;
import org.apache.calcite.rel.core.Exchange;
import org.apache.calcite.rel.core.Filter;
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.Union;
import org.apache.calcite.rel.core.Values;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.util.ImmutableBitSet;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
/**
* RelMdPopulationSize supplies a default implementation of
* {@link RelMetadataQuery#getPopulationSize} for the standard logical algebra.
*/
public class RelMdPopulationSize
implements MetadataHandler<BuiltInMetadata.PopulationSize> {
public static final RelMetadataProvider SOURCE =
ReflectiveRelMetadataProvider.reflectiveSource(
new RelMdPopulationSize(), BuiltInMetadata.PopulationSize.Handler.class);
//~ Constructors -----------------------------------------------------------
private RelMdPopulationSize() {}
//~ Methods ----------------------------------------------------------------
@Override public MetadataDef<BuiltInMetadata.PopulationSize> getDef() {
return BuiltInMetadata.PopulationSize.DEF;
}
public @Nullable Double getPopulationSize(Filter rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
return mq.getPopulationSize(rel.getInput(), groupKey);
}
public @Nullable Double getPopulationSize(Sort rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
return mq.getPopulationSize(rel.getInput(), groupKey);
}
public @Nullable Double getPopulationSize(Exchange rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
return mq.getPopulationSize(rel.getInput(), groupKey);
}
public @Nullable Double getPopulationSize(TableModify rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
return mq.getPopulationSize(rel.getInput(), groupKey);
}
public @Nullable Double getPopulationSize(Union rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
double population = 0.0;
for (RelNode input : rel.getInputs()) {
Double subPop = mq.getPopulationSize(input, groupKey);
if (subPop == null) {
return null;
}
population += subPop;
}
return population;
}
public @Nullable Double getPopulationSize(Join rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
return RelMdUtil.getJoinPopulationSize(mq, rel, groupKey);
}
public @Nullable Double getPopulationSize(Aggregate rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
ImmutableBitSet.Builder childKey = ImmutableBitSet.builder();
RelMdUtil.setAggChildKeys(groupKey, rel, childKey);
return mq.getPopulationSize(rel.getInput(), childKey.build());
}
public Double getPopulationSize(Values rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
// assume half the rows are duplicates
return rel.estimateRowCount(mq) / 2;
}
public @Nullable Double getPopulationSize(Project rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
// try to remove const columns from the group keys, as they do not
// affect the population size
ImmutableBitSet nonConstCols = RexUtil.getNonConstColumns(groupKey, rel.getProjects());
if (nonConstCols.cardinality() == 0) {
// all columns are constants, the population size should be 1
return 1D;
}
if (nonConstCols.cardinality() < groupKey.cardinality()) {
// some const columns can be removed, call the method recursively
// with the trimmed columns
return getPopulationSize(rel, mq, nonConstCols);
}
ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder();
ImmutableBitSet.Builder projCols = ImmutableBitSet.builder();
List<RexNode> projExprs = rel.getProjects();
RelMdUtil.splitCols(projExprs, groupKey, baseCols, projCols);
Double population =
mq.getPopulationSize(rel.getInput(), baseCols.build());
if (population == null) {
return null;
}
// No further computation required if the projection expressions are
// all column references
if (projCols.cardinality() == 0) {
return population;
}
for (int bit : projCols.build()) {
Double subRowCount =
RelMdUtil.cardOfProjExpr(mq, rel, projExprs.get(bit));
if (subRowCount == null) {
return null;
}
population *= subRowCount;
}
// REVIEW zfong 6/22/06 - Broadbase did not have the call to
// numDistinctVals. This is needed; otherwise, population can be
// larger than the number of rows in the RelNode.
return RelMdUtil.numDistinctVals(population, mq.getRowCount(rel));
}
/** Catch-all implementation for
* {@link BuiltInMetadata.PopulationSize#getPopulationSize(ImmutableBitSet)},
* invoked using reflection.
*
* @see org.apache.calcite.rel.metadata.RelMetadataQuery#getPopulationSize(RelNode, ImmutableBitSet)
*/
public @Nullable Double getPopulationSize(RelNode rel, RelMetadataQuery mq,
ImmutableBitSet groupKey) {
// if the keys are unique, return the row count; otherwise, we have
// no further information on which to return any legitimate value
// REVIEW zfong 4/11/06 - Broadbase code returns the product of each
// unique key, which would result in the population being larger
// than the total rows in the relnode
boolean uniq = RelMdUtil.areColumnsDefinitelyUnique(mq, rel, groupKey);
if (uniq) {
return mq.getRowCount(rel);
}
return null;
}
}