| /* |
| * 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; |
| |
| import org.apache.calcite.rex.RexBuilder; |
| import org.apache.calcite.rex.RexNode; |
| import org.apache.calcite.rex.RexUtil; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| |
| import java.util.Objects; |
| |
| /** |
| * Predicates that are known to hold in the output of a particular relational |
| * expression. |
| * |
| * <p><b>Pulled up predicates</b> (field {@link #pulledUpPredicates} are |
| * predicates that apply to every row output by the relational expression. They |
| * are inferred from the input relational expression(s) and the relational |
| * operator. |
| * |
| * <p>For example, if you apply {@code Filter(x > 1)} to a relational |
| * expression that has a predicate {@code y < 10} then the pulled up predicates |
| * for the Filter are {@code [y < 10, x > 1]}. |
| * |
| * <p><b>Inferred predicates</b> only apply to joins. If there there is a |
| * predicate on the left input to a join, and that predicate is over columns |
| * used in the join condition, then a predicate can be inferred on the right |
| * input to the join. (And vice versa.) |
| * |
| * <p>For example, in the query |
| * <blockquote>SELECT *<br> |
| * FROM emp<br> |
| * JOIN dept ON emp.deptno = dept.deptno |
| * WHERE emp.gender = 'F' AND emp.deptno < 10</blockquote> |
| * we have |
| * <ul> |
| * <li>left: {@code Filter(Scan(EMP), deptno < 10}, |
| * predicates: {@code [deptno < 10]} |
| * <li>right: {@code Scan(DEPT)}, predicates: {@code []} |
| * <li>join: {@code Join(left, right, emp.deptno = dept.deptno}, |
| * leftInferredPredicates: [], |
| * rightInferredPredicates: [deptno < 10], |
| * pulledUpPredicates: [emp.gender = 'F', emp.deptno < 10, |
| * emp.deptno = dept.deptno, dept.deptno < 10] |
| * </ul> |
| * |
| * <p>Note that the predicate from the left input appears in |
| * {@code rightInferredPredicates}. Predicates from several sources appear in |
| * {@code pulledUpPredicates}. |
| */ |
| public class RelOptPredicateList { |
| private static final ImmutableList<RexNode> EMPTY_LIST = ImmutableList.of(); |
| public static final RelOptPredicateList EMPTY = |
| new RelOptPredicateList(EMPTY_LIST, EMPTY_LIST, EMPTY_LIST, |
| ImmutableMap.of()); |
| |
| /** Predicates that can be pulled up from the relational expression and its |
| * inputs. */ |
| public final ImmutableList<RexNode> pulledUpPredicates; |
| |
| /** Predicates that were inferred from the right input. |
| * Empty if the relational expression is not a join. */ |
| public final ImmutableList<RexNode> leftInferredPredicates; |
| |
| /** Predicates that were inferred from the left input. |
| * Empty if the relational expression is not a join. */ |
| public final ImmutableList<RexNode> rightInferredPredicates; |
| |
| /** A map of each (e, constant) pair that occurs within |
| * {@link #pulledUpPredicates}. */ |
| public final ImmutableMap<RexNode, RexNode> constantMap; |
| |
| private RelOptPredicateList(ImmutableList<RexNode> pulledUpPredicates, |
| ImmutableList<RexNode> leftInferredPredicates, |
| ImmutableList<RexNode> rightInferredPredicates, |
| ImmutableMap<RexNode, RexNode> constantMap) { |
| this.pulledUpPredicates = Objects.requireNonNull(pulledUpPredicates); |
| this.leftInferredPredicates = |
| Objects.requireNonNull(leftInferredPredicates); |
| this.rightInferredPredicates = |
| Objects.requireNonNull(rightInferredPredicates); |
| this.constantMap = Objects.requireNonNull(constantMap); |
| } |
| |
| /** Creates a RelOptPredicateList with only pulled-up predicates, no inferred |
| * predicates. |
| * |
| * <p>Use this for relational expressions other than joins. |
| * |
| * @param pulledUpPredicates Predicates that apply to the rows returned by the |
| * relational expression |
| */ |
| public static RelOptPredicateList of(RexBuilder rexBuilder, |
| Iterable<RexNode> pulledUpPredicates) { |
| ImmutableList<RexNode> pulledUpPredicatesList = |
| ImmutableList.copyOf(pulledUpPredicates); |
| if (pulledUpPredicatesList.isEmpty()) { |
| return EMPTY; |
| } |
| return of(rexBuilder, pulledUpPredicatesList, EMPTY_LIST, EMPTY_LIST); |
| } |
| |
| /** Creates a RelOptPredicateList for a join. |
| * |
| * @param rexBuilder Rex builder |
| * @param pulledUpPredicates Predicates that apply to the rows returned by the |
| * relational expression |
| * @param leftInferredPredicates Predicates that were inferred from the right |
| * input |
| * @param rightInferredPredicates Predicates that were inferred from the left |
| * input |
| */ |
| public static RelOptPredicateList of(RexBuilder rexBuilder, |
| Iterable<RexNode> pulledUpPredicates, |
| Iterable<RexNode> leftInferredPredicates, |
| Iterable<RexNode> rightInferredPredicates) { |
| final ImmutableList<RexNode> pulledUpPredicatesList = |
| ImmutableList.copyOf(pulledUpPredicates); |
| final ImmutableList<RexNode> leftInferredPredicateList = |
| ImmutableList.copyOf(leftInferredPredicates); |
| final ImmutableList<RexNode> rightInferredPredicatesList = |
| ImmutableList.copyOf(rightInferredPredicates); |
| if (pulledUpPredicatesList.isEmpty() |
| && leftInferredPredicateList.isEmpty() |
| && rightInferredPredicatesList.isEmpty()) { |
| return EMPTY; |
| } |
| final ImmutableMap<RexNode, RexNode> constantMap = |
| RexUtil.predicateConstants(RexNode.class, rexBuilder, |
| pulledUpPredicatesList); |
| return new RelOptPredicateList(pulledUpPredicatesList, |
| leftInferredPredicateList, rightInferredPredicatesList, constantMap); |
| } |
| |
| public RelOptPredicateList union(RexBuilder rexBuilder, |
| RelOptPredicateList list) { |
| if (this == EMPTY) { |
| return list; |
| } else if (list == EMPTY) { |
| return this; |
| } else { |
| return RelOptPredicateList.of(rexBuilder, |
| concat(pulledUpPredicates, list.pulledUpPredicates), |
| concat(leftInferredPredicates, list.leftInferredPredicates), |
| concat(rightInferredPredicates, list.rightInferredPredicates)); |
| } |
| } |
| |
| /** Concatenates two immutable lists, avoiding a copy it possible. */ |
| private static <E> ImmutableList<E> concat(ImmutableList<E> list1, |
| ImmutableList<E> list2) { |
| if (list1.isEmpty()) { |
| return list2; |
| } else if (list2.isEmpty()) { |
| return list1; |
| } else { |
| return ImmutableList.<E>builder().addAll(list1).addAll(list2).build(); |
| } |
| } |
| |
| public RelOptPredicateList shift(RexBuilder rexBuilder, int offset) { |
| return RelOptPredicateList.of(rexBuilder, |
| RexUtil.shift(pulledUpPredicates, offset), |
| RexUtil.shift(leftInferredPredicates, offset), |
| RexUtil.shift(rightInferredPredicates, offset)); |
| } |
| } |
| |
| // End RelOptPredicateList.java |