Package org.eigenbase.rel.rules

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

/*
* 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.eigenbase.rel.rules;

import java.util.*;

import org.eigenbase.rel.*;
import org.eigenbase.rel.RelFactories.ProjectFactory;
import org.eigenbase.relopt.*;
import org.eigenbase.rex.*;
import org.eigenbase.util.Permutation;

/**
* MergeProjectRule merges a {@link ProjectRelBase} into
* another {@link ProjectRelBase},
* provided the projects aren't projecting identical sets of input references.
*/
public class MergeProjectRule extends RelOptRule {
  public static final MergeProjectRule INSTANCE =
      new MergeProjectRule();

  //~ Instance fields --------------------------------------------------------

  /**
   * if true, always merge projects
   */
  private final boolean force;

  private final ProjectFactory projectFactory;

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

  /**
   * Creates a MergeProjectRule.
   */
  private MergeProjectRule() {
    this(false, RelFactories.DEFAULT_PROJECT_FACTORY);
  }

  /**
   * Creates a MergeProjectRule, specifying whether to always merge projects.
   *
   * @param force Whether to always merge projects
   */
  public MergeProjectRule(boolean force, ProjectFactory pFactory) {
    super(
        operand(ProjectRelBase.class,
            operand(ProjectRelBase.class, any())),
        "MergeProjectRule" + (force ? ": force mode" : ""));
    this.force = force;
    projectFactory = pFactory;
  }

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

  // implement RelOptRule
  public void onMatch(RelOptRuleCall call) {
    ProjectRelBase topProject = call.rel(0);
    ProjectRelBase bottomProject = call.rel(1);
    RexBuilder rexBuilder = topProject.getCluster().getRexBuilder();

    // If one or both projects are permutations, short-circuit the complex logic
    // of building a RexProgram.
    final Permutation topPermutation = topProject.getPermutation();
    if (topPermutation != null) {
      if (topPermutation.isIdentity()) {
        // Let RemoveTrivialProjectRule handle this.
        return;
      }
      final Permutation bottomPermutation = bottomProject.getPermutation();
      if (bottomPermutation != null) {
        if (bottomPermutation.isIdentity()) {
          // Let RemoveTrivialProjectRule handle this.
          return;
        }
        final Permutation product = topPermutation.product(bottomPermutation);
        call.transformTo(
            RelOptUtil.projectMapping(bottomProject.getChild(),
                product.inverse(), topProject.getRowType().getFieldNames(),
                projectFactory));
        return;
      }
    }

    // if we're not in force mode and the two projects reference identical
    // inputs, then return and either let FennelRenameRule or
    // RemoveTrivialProjectRule replace the projects
    if (!force) {
      if (RelOptUtil.checkProjAndChildInputs(topProject, false)) {
        return;
      }
    }

    // create a RexProgram for the bottom project
    RexProgram bottomProgram =
        RexProgram.create(
            bottomProject.getChild().getRowType(),
            bottomProject.getProjects(),
            null,
            bottomProject.getRowType(),
            rexBuilder);

    // create a RexProgram for the topmost project
    List<RexNode> projExprs = topProject.getProjects();
    RexProgram topProgram =
        RexProgram.create(
            bottomProject.getRowType(),
            projExprs,
            null,
            topProject.getRowType(),
            rexBuilder);

    // combine the two RexPrograms
    RexProgram mergedProgram =
        RexProgramBuilder.mergePrograms(
            topProgram,
            bottomProgram,
            rexBuilder);

    // re-expand the topmost projection expressions, now that they
    // reference the children of the bottom-most project
    int nProjExprs = projExprs.size();
    List<RexNode> newProjExprs = new ArrayList<RexNode>();
    List<RexLocalRef> projList = mergedProgram.getProjectList();
    for (int i = 0; i < nProjExprs; i++) {
      newProjExprs.add(mergedProgram.expandLocalRef(projList.get(i)));
    }

    // replace the two projects with a combined projection
    RelNode newProjectRel = projectFactory.createProject(
        bottomProject.getChild(), newProjExprs,
        topProject.getRowType().getFieldNames());

    call.transformTo(newProjectRel);
  }
}

// End MergeProjectRule.java
TOP

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

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.