| /* |
| * 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.adapter.enumerable.EnumerableLimit; |
| import org.apache.calcite.plan.volcano.RelSubset; |
| import org.apache.calcite.rel.RelNode; |
| import org.apache.calcite.rel.core.Aggregate; |
| import org.apache.calcite.rel.core.Calc; |
| import org.apache.calcite.rel.core.Exchange; |
| import org.apache.calcite.rel.core.Filter; |
| import org.apache.calcite.rel.core.Intersect; |
| import org.apache.calcite.rel.core.Join; |
| import org.apache.calcite.rel.core.Minus; |
| 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.RexLiteral; |
| import org.apache.calcite.util.Bug; |
| import org.apache.calcite.util.Util; |
| |
| import org.checkerframework.checker.nullness.qual.Nullable; |
| |
| /** |
| * RelMdMinRowCount supplies a default implementation of |
| * {@link RelMetadataQuery#getMinRowCount} for the standard logical algebra. |
| */ |
| public class RelMdMinRowCount |
| implements MetadataHandler<BuiltInMetadata.MinRowCount> { |
| public static final RelMetadataProvider SOURCE = |
| ReflectiveRelMetadataProvider.reflectiveSource( |
| new RelMdMinRowCount(), BuiltInMetadata.MinRowCount.Handler.class); |
| |
| //~ Methods ---------------------------------------------------------------- |
| |
| @Override public MetadataDef<BuiltInMetadata.MinRowCount> getDef() { |
| return BuiltInMetadata.MinRowCount.DEF; |
| } |
| |
| public Double getMinRowCount(Union rel, RelMetadataQuery mq) { |
| double rowCount = 0.0; |
| for (RelNode input : rel.getInputs()) { |
| Double partialRowCount = mq.getMinRowCount(input); |
| if (partialRowCount != null) { |
| rowCount += partialRowCount; |
| } |
| } |
| |
| if (rel.all) { |
| return rowCount; |
| } else { |
| return Math.min(rowCount, 1d); |
| } |
| } |
| |
| public Double getMinRowCount(Intersect rel, RelMetadataQuery mq) { |
| return 0d; // no lower bound |
| } |
| |
| public Double getMinRowCount(Minus rel, RelMetadataQuery mq) { |
| return 0d; // no lower bound |
| } |
| |
| public Double getMinRowCount(Filter rel, RelMetadataQuery mq) { |
| return 0d; // no lower bound |
| } |
| |
| public @Nullable Double getMinRowCount(Calc rel, RelMetadataQuery mq) { |
| if (rel.getProgram().getCondition() != null) { |
| // no lower bound |
| return 0d; |
| } else { |
| return mq.getMinRowCount(rel.getInput()); |
| } |
| } |
| |
| public @Nullable Double getMinRowCount(Project rel, RelMetadataQuery mq) { |
| return mq.getMinRowCount(rel.getInput()); |
| } |
| |
| public @Nullable Double getMinRowCount(Exchange rel, RelMetadataQuery mq) { |
| return mq.getMinRowCount(rel.getInput()); |
| } |
| |
| public @Nullable Double getMinRowCount(TableModify rel, RelMetadataQuery mq) { |
| return mq.getMinRowCount(rel.getInput()); |
| } |
| |
| public Double getMinRowCount(Sort rel, RelMetadataQuery mq) { |
| Double rowCount = mq.getMinRowCount(rel.getInput()); |
| if (rowCount == null) { |
| rowCount = 0D; |
| } |
| final int offset = rel.offset == null ? 0 : RexLiteral.intValue(rel.offset); |
| rowCount = Math.max(rowCount - offset, 0D); |
| |
| if (rel.fetch != null) { |
| final int limit = RexLiteral.intValue(rel.fetch); |
| if (limit < rowCount) { |
| return (double) limit; |
| } |
| } |
| return rowCount; |
| } |
| |
| public Double getMinRowCount(EnumerableLimit rel, RelMetadataQuery mq) { |
| Double rowCount = mq.getMinRowCount(rel.getInput()); |
| if (rowCount == null) { |
| rowCount = 0D; |
| } |
| final int offset = rel.offset == null ? 0 : RexLiteral.intValue(rel.offset); |
| rowCount = Math.max(rowCount - offset, 0D); |
| |
| if (rel.fetch != null) { |
| final int limit = RexLiteral.intValue(rel.fetch); |
| if (limit < rowCount) { |
| return (double) limit; |
| } |
| } |
| return rowCount; |
| } |
| |
| public Double getMinRowCount(Aggregate rel, RelMetadataQuery mq) { |
| if (rel.getGroupSet().isEmpty()) { |
| // Aggregate with no GROUP BY always returns 1 row (even on empty table). |
| return 1D; |
| } |
| final Double rowCount = mq.getMinRowCount(rel.getInput()); |
| if (rowCount != null && rowCount >= 1D) { |
| return (double) rel.getGroupSets().size(); |
| } |
| return 0D; |
| } |
| |
| public Double getMinRowCount(Join rel, RelMetadataQuery mq) { |
| return 0D; |
| } |
| |
| public Double getMinRowCount(TableScan rel, RelMetadataQuery mq) { |
| return 0D; |
| } |
| |
| public Double getMinRowCount(Values values, RelMetadataQuery mq) { |
| // For Values, the minimum row count is the actual row count. |
| return (double) values.getTuples().size(); |
| } |
| |
| public Double getMinRowCount(RelSubset rel, RelMetadataQuery mq) { |
| // FIXME This is a short-term fix for [CALCITE-1018]. A complete |
| // solution will come with [CALCITE-1048]. |
| Util.discard(Bug.CALCITE_1048_FIXED); |
| for (RelNode node : rel.getRels()) { |
| if (node instanceof Sort) { |
| Sort sort = (Sort) node; |
| if (sort.fetch != null) { |
| return (double) RexLiteral.intValue(sort.fetch); |
| } |
| } |
| } |
| |
| return 0D; |
| } |
| |
| // Catch-all rule when none of the others apply. |
| public @Nullable Double getMinRowCount(RelNode rel, RelMetadataQuery mq) { |
| return null; |
| } |
| } |