Package org.eigenbase.rel.rules

Source Code of org.eigenbase.rel.rules.LoptMultiJoin

/*
// Licensed to Julian Hyde under one or more contributor license
// agreements. See the NOTICE file distributed with this work for
// additional information regarding copyright ownership.
//
// Julian Hyde 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.eigenbase.rel.rules;

import java.util.*;

import org.eigenbase.rel.*;
import org.eigenbase.rel.metadata.*;
import org.eigenbase.relopt.*;
import org.eigenbase.reltype.*;
import org.eigenbase.rex.*;
import org.eigenbase.sql.SqlKind;
import org.eigenbase.util.IntList;

import net.hydromatic.optiq.util.BitSets;

/**
* Utility class that keeps track of the join factors that
* make up a {@link MultiJoinRel}.
*/
public class LoptMultiJoin {
  //~ Instance fields --------------------------------------------------------

  /**
   * The MultiJoinRel being optimized
   */
  MultiJoinRel multiJoin;

  /**
   * Join filters associated with the MultiJoinRel, decomposed into a list.
   * Excludes left/right outer join filters.
   */
  private List<RexNode> joinFilters;

  /**
   * All join filters associated with the MultiJoinRel, decomposed into a
   * list. Includes left/right outer join filters.
   */
  private List<RexNode> allJoinFilters;

  /**
   * Number of factors into the MultiJoinRel
   */
  private int nJoinFactors;

  /**
   * Total number of fields in the MultiJoinRel
   */
  private int nTotalFields;

  /**
   * Original inputs into the MultiJoinRel
   */
  private List<RelNode> joinFactors;

  /**
   * If a join factor is null generating in a left or right outer join,
   * joinTypes indicates the join type corresponding to the factor. Otherwise,
   * it is set to INNER.
   */
  private List<JoinRelType> joinTypes;

  /**
   * If a join factor is null generating in a left or right outer join, the
   * bitmap contains the non-null generating factors that the null generating
   * factor is dependent upon
   */
  private BitSet [] outerJoinFactors;

  /**
   * Bitmap corresponding to the fields projected from each join factor, after
   * row scan processing has completed. This excludes fields referenced in
   * join conditions, unless the field appears in the final projection list.
   */
  private List<BitSet> projFields;

  /**
   * Map containing reference counts of the fields referenced in join
   * conditions for each join factor. If a field is only required for a
   * semijoin, then it is removed from the reference count. (Hence the need
   * for reference counts instead of simply a bitmap.) The map is indexed by
   * the factor number.
   */
  private Map<Integer, int[]> joinFieldRefCountsMap;

  /**
   * For each join filter, associates a bitmap indicating all factors
   * referenced by the filter
   */
  private Map<RexNode, BitSet> factorsRefByJoinFilter;

  /**
   * For each join filter, associates a bitmap indicating all fields
   * referenced by the filter
   */
  private Map<RexNode, BitSet> fieldsRefByJoinFilter;

  /**
   * Starting RexInputRef index corresponding to each join factor
   */
  int [] joinStart;

  /**
   * Number of fields in each join factor
   */
  int [] nFieldsInJoinFactor;

  /**
   * Bitmap indicating which factors each factor references in join filters
   * that correspond to comparisons
   */
  BitSet [] factorsRefByFactor;

  /**
   * Weights of each factor combination
   */
  int [][] factorWeights;

  /**
   * Type factory
   */
  RelDataTypeFactory factory;

  /**
   * Indicates for each factor whether its join can be removed because it is
   * the dimension table in a semijoin. If it can be, the entry indicates the
   * factor id of the fact table (corresponding to the dimension table) in the
   * semijoin that allows the factor to be removed. If the factor cannot be
   * removed, the entry corresponding to the factor is null.
   */
  Integer [] joinRemovalFactors;

  /**
   * The semijoins that allow the join of a dimension table to be removed
   */
  SemiJoinRel [] joinRemovalSemiJoins;

  /**
   * Set of null-generating factors whose corresponding outer join can be
   * removed from the query plan
   */
  Set<Integer> removableOuterJoinFactors;

  /**
   * Map consisting of all pairs of self-joins where the self-join can be
   * removed because the join between the identical factors is an equality
   * join on the same set of unique keys. The map is keyed by either factor in
   * the self join.
   */
  Map<Integer, RemovableSelfJoin> removableSelfJoinPairs;

  //~ Constructors -----------------------------------------------------------

  public LoptMultiJoin(MultiJoinRel multiJoin) {
    this.multiJoin = multiJoin;
    joinFactors = multiJoin.getInputs();
    nJoinFactors = joinFactors.size();
    projFields = multiJoin.getProjFields();
    joinFieldRefCountsMap = multiJoin.getCopyJoinFieldRefCountsMap();

    joinFilters = new ArrayList<RexNode>();
    RelOptUtil.decomposeConjunction(
        multiJoin.getJoinFilter(),
        joinFilters);

    allJoinFilters = new ArrayList<RexNode>(joinFilters);
    List<RexNode> outerJoinFilters = multiJoin.getOuterJoinConditions();
    for (int i = 0; i < nJoinFactors; i++) {
      List<RexNode> ojFilters = new ArrayList<RexNode>();
      RelOptUtil.decomposeConjunction(outerJoinFilters.get(i), ojFilters);
      allJoinFilters.addAll(ojFilters);
    }

    int start = 0;
    nTotalFields = multiJoin.getRowType().getFieldCount();
    joinStart = new int[nJoinFactors];
    nFieldsInJoinFactor = new int[nJoinFactors];
    for (int i = 0; i < nJoinFactors; i++) {
      joinStart[i] = start;
      nFieldsInJoinFactor[i] =
          joinFactors.get(i).getRowType().getFieldCount();
      start += nFieldsInJoinFactor[i];
    }

    setOuterJoinInfo();

    // determine which join factors each join filter references
    setJoinFilterRefs();

    factory = multiJoin.getCluster().getTypeFactory();

    joinRemovalFactors = new Integer[nJoinFactors];
    joinRemovalSemiJoins = new SemiJoinRel[nJoinFactors];

    removableOuterJoinFactors = new HashSet<Integer>();
    removableSelfJoinPairs = new HashMap<Integer, RemovableSelfJoin>();
  }

  //~ Methods ----------------------------------------------------------------

  /**
   * @return the MultiJoinRel corresponding to this multijoin
   */
  public MultiJoinRel getMultiJoinRel() {
    return multiJoin;
  }

  /**
   * @return number of factors in this multijoin
   */
  public int getNumJoinFactors() {
    return nJoinFactors;
  }

  /**
   * @param factIdx factor to be returned
   *
   * @return factor corresponding to the factor index passed in
   */
  public RelNode getJoinFactor(int factIdx) {
    return joinFactors.get(factIdx);
  }

  /**
   * @return total number of fields in the multijoin
   */
  public int getNumTotalFields() {
    return nTotalFields;
  }

  /**
   * @param factIdx desired factor
   *
   * @return number of fields in the specified factor
   */
  public int getNumFieldsInJoinFactor(int factIdx) {
    return nFieldsInJoinFactor[factIdx];
  }

  /**
   * @return all non-outer join filters in this multijoin
   */
  public List<RexNode> getJoinFilters() {
    return joinFilters;
  }

  /**
   * @param joinFilter filter for which information will be returned
   *
   * @return bitmap corresponding to the factors referenced within the
   * specified join filter
   */
  public BitSet getFactorsRefByJoinFilter(RexNode joinFilter) {
    return factorsRefByJoinFilter.get(joinFilter);
  }

  /**
   * Returns array of fields contained within the multi-join
   */
  public List<RelDataTypeField> getMultiJoinFields() {
    return multiJoin.getRowType().getFieldList();
  }

  /**
   * @param joinFilter the filter for which information will be returned
   *
   * @return bitmap corresponding to the fields referenced by a join filter
   */
  public BitSet getFieldsRefByJoinFilter(RexNode joinFilter) {
    return fieldsRefByJoinFilter.get(joinFilter);
  }

  /**
   * @return weights of the different factors relative to one another
   */
  public int [][] getFactorWeights() {
    return factorWeights;
  }

  /**
   * @param factIdx factor for which information will be returned
   *
   * @return bitmap corresponding to the factors referenced by the specified
   * factor in the various join filters that correspond to comparisons
   */
  public BitSet getFactorsRefByFactor(int factIdx) {
    return factorsRefByFactor[factIdx];
  }

  /**
   * @param factIdx factor for which information will be returned
   *
   * @return starting offset within the multijoin for the specified factor
   */
  public int getJoinStart(int factIdx) {
    return joinStart[factIdx];
  }

  /**
   * @param factIdx factor for which information will be returned
   *
   * @return whether or not the factor corresponds to a null-generating factor
   * in a left or right outer join
   */
  public boolean isNullGenerating(int factIdx) {
    return joinTypes.get(factIdx) != JoinRelType.INNER;
  }

  /**
   * @param factIdx factor for which information will be returned
   *
   * @return bitmap containing the factors that a null generating factor is
   * dependent upon, if the factor is null generating in a left or right outer
   * join; otherwise null is returned
   */
  public BitSet getOuterJoinFactors(int factIdx) {
    return outerJoinFactors[factIdx];
  }

  /**
   * @param factIdx factor for which information will be returned
   *
   * @return outer join conditions associated with the specified null
   * generating factor
   */
  public RexNode getOuterJoinCond(int factIdx) {
    return multiJoin.getOuterJoinConditions().get(factIdx);
  }

  /**
   * @param factIdx factor for which information will be returned
   *
   * @return bitmap containing the fields that are projected from a factor
   */
  public BitSet getProjFields(int factIdx) {
    return projFields.get(factIdx);
  }

  /**
   * @param factIdx factor for which information will be returned
   *
   * @return the join field reference counts for a factor
   */
  public int [] getJoinFieldRefCounts(int factIdx) {
    return joinFieldRefCountsMap.get(factIdx);
  }

  /**
   * @param dimIdx the dimension factor for which information will be returned
   *
   * @return the factor id of the fact table corresponding to a dimension
   * table in a semijoin, in the case where the join with the dimension table
   * can be removed
   */
  public Integer getJoinRemovalFactor(int dimIdx) {
    return joinRemovalFactors[dimIdx];
  }

  /**
   * @param dimIdx the dimension factor for which information will be returned
   *
   * @return the semijoin that allows the join of a dimension table to be
   * removed
   */
  public SemiJoinRel getJoinRemovalSemiJoin(int dimIdx) {
    return joinRemovalSemiJoins[dimIdx];
  }

  /**
   * Indicates that a dimension factor's join can be removed because of a
   * semijoin with a fact table.
   *
   * @param dimIdx id of the dimension factor
   * @param factIdx id of the fact factor
   */
  public void setJoinRemovalFactor(int dimIdx, int factIdx) {
    joinRemovalFactors[dimIdx] = factIdx;
  }

  /**
   * Indicates the semijoin that allows the join of a dimension table to be
   * removed
   *
   * @param dimIdx id of the dimension factor
   * @param semiJoin the semijoin
   */
  public void setJoinRemovalSemiJoin(int dimIdx, SemiJoinRel semiJoin) {
    joinRemovalSemiJoins[dimIdx] = semiJoin;
  }

  /**
   * Extracts outer join information from the join factors, including the type
   * of outer join and the factors that a null-generating factor is dependent
   * upon.
   */
  private void setOuterJoinInfo() {
    joinTypes = multiJoin.getJoinTypes();
    List<RexNode> outerJoinConds = multiJoin.getOuterJoinConditions();
    outerJoinFactors = new BitSet[nJoinFactors];
    for (int i = 0; i < nJoinFactors; i++) {
      if (outerJoinConds.get(i) != null) {
        // set a bitmap containing the factors referenced in the
        // ON condition of the outer join; mask off the factor
        // corresponding to the factor itself
        BitSet dependentFactors =
            getJoinFilterFactorBitmap(outerJoinConds.get(i), false);
        dependentFactors.clear(i);
        outerJoinFactors[i] = dependentFactors;
      }
    }
  }

  /**
   * Returns a bitmap representing the factors referenced in a join filter
   *
   * @param joinFilter the join filter
   * @param setFields if true, add the fields referenced by the join filter
   * into a map
   *
   * @return the bitmap containing the factor references
   */
  private BitSet getJoinFilterFactorBitmap(
      RexNode joinFilter,
      boolean setFields) {
    BitSet fieldRefBitmap = new BitSet(nTotalFields);
    joinFilter.accept(new RelOptUtil.InputFinder(fieldRefBitmap));
    if (setFields) {
      fieldsRefByJoinFilter.put(joinFilter, fieldRefBitmap);
    }

    BitSet factorRefBitmap = new BitSet(nJoinFactors);
    setFactorBitmap(factorRefBitmap, fieldRefBitmap);
    return factorRefBitmap;
  }

  /**
   * Sets bitmaps indicating which factors and fields each join filter
   * references
   */
  private void setJoinFilterRefs() {
    fieldsRefByJoinFilter = new HashMap<RexNode, BitSet>();
    factorsRefByJoinFilter = new HashMap<RexNode, BitSet>();
    ListIterator<RexNode> filterIter = allJoinFilters.listIterator();
    while (filterIter.hasNext()) {
      RexNode joinFilter = filterIter.next();

      // ignore the literal filter; if necessary, we'll add it back
      // later
      if (joinFilter.isAlwaysTrue()) {
        filterIter.remove();
      }
      BitSet factorRefBitmap =
          getJoinFilterFactorBitmap(joinFilter, true);
      factorsRefByJoinFilter.put(joinFilter, factorRefBitmap);
    }
  }

  /**
   * Sets the bitmap indicating which factors a filter references based on
   * which fields it references
   *
   * @param factorRefBitmap bitmap representing factors referenced that will
   * be set by this method
   * @param fieldRefBitmap bitmap representing fields referenced
   */
  private void setFactorBitmap(
      BitSet factorRefBitmap,
      BitSet fieldRefBitmap) {
    for (int field : BitSets.toIter(fieldRefBitmap)) {
      int factor = findRef(field);
      factorRefBitmap.set(factor);
    }
  }

  /**
   * Determines the join factor corresponding to a RexInputRef
   *
   * @param rexInputRef rexInputRef index
   *
   * @return index corresponding to join factor
   */
  public int findRef(int rexInputRef) {
    for (int i = 0; i < nJoinFactors; i++) {
      if ((rexInputRef >= joinStart[i])
          && (rexInputRef < (joinStart[i] + nFieldsInJoinFactor[i]))) {
        return i;
      }
    }
    throw new AssertionError();
  }

  /**
   * Sets weighting for each combination of factors, depending on which join
   * filters reference which factors. Greater weight is given to equality
   * conditions. Also, sets bitmaps indicating which factors are referenced by
   * each factor within join filters that are comparisons.
   */
  public void setFactorWeights() {
    factorWeights = new int[nJoinFactors][nJoinFactors];
    factorsRefByFactor = new BitSet[nJoinFactors];
    for (int i = 0; i < nJoinFactors; i++) {
      factorsRefByFactor[i] = new BitSet(nJoinFactors);
    }

    for (RexNode joinFilter : allJoinFilters) {
      BitSet factorRefs = factorsRefByJoinFilter.get(joinFilter);

      // don't give weights to non-comparison expressions
      if (!(joinFilter instanceof RexCall)) {
        continue;
      }
      if (!joinFilter.isA(SqlKind.COMPARISON)) {
        continue;
      }

      // OR the factors referenced in this join filter into the
      // bitmaps corresponding to each of the factors; however,
      // exclude the bit corresponding to the factor itself
      for (int factor : BitSets.toIter(factorRefs)) {
        factorsRefByFactor[factor].or(factorRefs);
        factorsRefByFactor[factor].clear(factor);
      }

      if (factorRefs.cardinality() == 2) {
        int leftFactor = factorRefs.nextSetBit(0);
        int rightFactor = factorRefs.nextSetBit(leftFactor + 1);

        BitSet leftFields = new BitSet(nTotalFields);
        List<RexNode> operands = ((RexCall) joinFilter).getOperands();
        operands.get(0).accept(new RelOptUtil.InputFinder(leftFields));
        BitSet leftBitmap = new BitSet(nJoinFactors);
        setFactorBitmap(leftBitmap, leftFields);

        // filter contains only two factor references, one on each
        // side of the operator
        int weight;
        if (leftBitmap.cardinality() == 1) {
          // give higher weight to equi-joins
          switch (joinFilter.getKind()) {
          case EQUALS:
            weight = 3;
            break;
          default:
            weight = 2;
          }
        } else {
          // cross product of two tables
          weight = 1;
        }
        setFactorWeight(weight, leftFactor, rightFactor);
      } else {
        // multiple factor references -- set a weight for each
        // combination of factors referenced within the filter
        final IntList list = BitSets.toList(factorRefs);
        for (int outer : list) {
          for (int inner : list) {
            if (outer != inner) {
              setFactorWeight(1, outer, inner);
            }
          }
        }
      }
    }
  }

  /**
   * Sets an individual weight if the new weight is better than the current
   * one
   *
   * @param weight weight to be set
   * @param leftFactor index of left factor
   * @param rightFactor index of right factor
   */
  private void setFactorWeight(int weight, int leftFactor, int rightFactor) {
    if (factorWeights[leftFactor][rightFactor] < weight) {
      factorWeights[leftFactor][rightFactor] = weight;
      factorWeights[rightFactor][leftFactor] = weight;
    }
  }

  /**
   * Returns true if a join tree contains all factors required
   *
   * @param joinTree join tree to be examined
   * @param factorsNeeded bitmap of factors required
   *
   * @return true if join tree contains all required factors
   */
  public boolean hasAllFactors(
      LoptJoinTree joinTree,
      BitSet factorsNeeded) {
    BitSet childFactors = new BitSet(nJoinFactors);
    getChildFactors(joinTree, childFactors);
    return BitSets.contains(childFactors, factorsNeeded);
  }

  /**
   * Sets a bitmap representing all fields corresponding to a RelNode
   *
   * @param rel Relational expression for which fields will be set
   * @param fields bitmap containing set bits for each field in a RelNode
   */
  public void setFieldBitmap(LoptJoinTree rel, BitSet fields) {
    // iterate through all factors within the RelNode
    BitSet factors = new BitSet(nJoinFactors);
    getChildFactors(rel, factors);
    for (int factor = factors.nextSetBit(0);
        factor >= 0;
        factor = factors.nextSetBit(factor + 1)) {
      // set a bit for each field
      for (int i = 0; i < nFieldsInJoinFactor[factor]; i++) {
        fields.set(joinStart[factor] + i);
      }
    }
  }

  /**
   * Sets a bitmap indicating all child RelNodes in a join tree
   *
   * @param joinTree join tree to be examined
   * @param childFactors bitmap to be set
   */
  public void getChildFactors(LoptJoinTree joinTree, BitSet childFactors) {
    List<Integer> children = new ArrayList<Integer>();
    joinTree.getTreeOrder(children);
    for (int child : children) {
      childFactors.set(child);
    }
  }

  /**
   * Retrieves the fields corresponding to a join between a left and right
   * tree
   *
   * @param left left hand side of the join
   * @param right right hand side of the join
   *
   * @return fields of the join
   */
  public List<RelDataTypeField> getJoinFields(
      LoptJoinTree left,
      LoptJoinTree right) {
    RelDataType rowType =
        factory.createJoinType(
            left.getJoinTree().getRowType(),
            right.getJoinTree().getRowType());
    return rowType.getFieldList();
  }

  /**
   * Adds a join factor to the set of factors that can be removed because the
   * factor is the null generating factor in an outer join, its join keys are
   * unique, and the factor is not projected in the query
   *
   * @param factIdx join factor
   */
  public void addRemovableOuterJoinFactor(int factIdx) {
    removableOuterJoinFactors.add(factIdx);
  }

  /**
   * @param factIdx factor in question
   *
   * @return true if the factor corresponds to the null generating factor in
   * an outer join that can be removed
   */
  public boolean isRemovableOuterJoinFactor(int factIdx) {
    return removableOuterJoinFactors.contains(factIdx);
  }

  /**
   * Adds to a map that keeps track of removable self-join pairs.
   *
   * @param factor1 one of the factors in the self-join
   * @param factor2 the second factor in the self-join
   */
  public void addRemovableSelfJoinPair(int factor1, int factor2) {
    int leftFactor;
    int rightFactor;

    // Put the factor with more fields on the left so it will be
    // preserved after the self-join is removed.
    if (getNumFieldsInJoinFactor(factor1)
        > getNumFieldsInJoinFactor(factor2)) {
      leftFactor = factor1;
      rightFactor = factor2;
    } else {
      leftFactor = factor2;
      rightFactor = factor1;
    }

    // Compute a column mapping such that if a column from the right
    // factor is also referenced in the left factor, we will map the
    // right reference to the left to avoid redundant references.
    Map<Integer, Integer> columnMapping = new HashMap<Integer, Integer>();

    // First, locate the originating column for all simple column
    // references in the left factor.
    RelNode left = getJoinFactor(leftFactor);
    Map<Integer, Integer> leftFactorColMapping =
        new HashMap<Integer, Integer>();
    for (int i = 0; i < left.getRowType().getFieldCount(); i++) {
      RelColumnOrigin colOrigin = RelMetadataQuery.getColumnOrigin(left, i);
      if (colOrigin != null) {
        leftFactorColMapping.put(
            colOrigin.getOriginColumnOrdinal(),
            i);
      }
    }

    // Then, see if the right factor references any of the same columns
    // by locating their originating columns.  If there are matches,
    // then we want to store the corresponding offset into the left
    // factor.
    RelNode right = getJoinFactor(rightFactor);
    for (int i = 0; i < right.getRowType().getFieldCount(); i++) {
      final RelColumnOrigin colOrigin =
          RelMetadataQuery.getColumnOrigin(right, i);
      if (colOrigin == null) {
        continue;
      }
      Integer leftOffset =
          leftFactorColMapping.get(colOrigin.getOriginColumnOrdinal());
      if (leftOffset == null) {
        continue;
      }
      columnMapping.put(i, leftOffset);
    }

    RemovableSelfJoin selfJoin =
        new RemovableSelfJoin(leftFactor, rightFactor, columnMapping);

    removableSelfJoinPairs.put(leftFactor, selfJoin);
    removableSelfJoinPairs.put(rightFactor, selfJoin);
  }

  /**
   * Returns the other factor in a self-join pair if the factor passed in is
   * a factor in a removable self-join; otherwise, returns null.
   *
   * @param factIdx one of the factors in a self-join pair
   */
  public Integer getOtherSelfJoinFactor(int factIdx) {
    RemovableSelfJoin selfJoin = removableSelfJoinPairs.get(factIdx);
    if (selfJoin == null) {
      return null;
    } else if (selfJoin.getRightFactor() == factIdx) {
      return selfJoin.getLeftFactor();
    } else {
      return selfJoin.getRightFactor();
    }
  }

  /**
   * @param factIdx factor in a self-join
   *
   * @return true if the factor is the left factor in a self-join
   */
  public boolean isLeftFactorInRemovableSelfJoin(int factIdx) {
    RemovableSelfJoin selfJoin = removableSelfJoinPairs.get(factIdx);
    if (selfJoin == null) {
      return false;
    }
    return selfJoin.getLeftFactor() == factIdx;
  }

  /**
   * @param factIdx factor in a self-join
   *
   * @return true if the factor is the right factor in a self-join
   */
  public boolean isRightFactorInRemovableSelfJoin(int factIdx) {
    RemovableSelfJoin selfJoin = removableSelfJoinPairs.get(factIdx);
    if (selfJoin == null) {
      return false;
    }
    return selfJoin.getRightFactor() == factIdx;
  }

  /**
   * Determines whether there is a mapping from a column in the right factor
   * of a self-join to a column from the left factor. Assumes that the right
   * factor is a part of a self-join.
   *
   * @param rightFactor the index of the right factor
   * @param rightOffset the column offset of the right factor
   *
   * @return the offset of the corresponding column in the left factor, if
   * such a column mapping exists; otherwise, null is returned
   */
  public Integer getRightColumnMapping(int rightFactor, int rightOffset) {
    RemovableSelfJoin selfJoin = removableSelfJoinPairs.get(rightFactor);
    assert selfJoin.getRightFactor() == rightFactor;
    return selfJoin.getColumnMapping().get(rightOffset);
  }

  //~ Inner Classes ----------------------------------------------------------

  /**
   * Utility class used to keep track of the factors in a removable self-join.
   * The right factor in the self-join is the one that will be removed.
   */
  private class RemovableSelfJoin {
    /**
     * The left factor in a removable self-join
     */
    private int leftFactor;

    /**
     * The right factor in a removable self-join, namely the factor that
     * will be removed
     */
    private int rightFactor;

    /**
     * A mapping that maps references to columns from the right factor to
     * columns in the left factor, if the column is referenced in both
     * factors
     */
    private Map<Integer, Integer> columnMapping;

    RemovableSelfJoin(
        int leftFactor,
        int rightFactor,
        Map<Integer, Integer> columnMapping) {
      this.leftFactor = leftFactor;
      this.rightFactor = rightFactor;
      this.columnMapping = columnMapping;
    }

    public int getLeftFactor() {
      return leftFactor;
    }

    public int getRightFactor() {
      return rightFactor;
    }

    public Map<Integer, Integer> getColumnMapping() {
      return columnMapping;
    }
  }
}

// End LoptMultiJoin.java
TOP

Related Classes of org.eigenbase.rel.rules.LoptMultiJoin

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.