Пример #1
0
  /**
   * Combines the join filters from the left and right inputs (if they are MultiJoinRels) with the
   * join filter in the joinrel into a single AND'd join filter, unless the inputs correspond to
   * null generating inputs in an outer join
   *
   * @param joinRel join rel
   * @param left left child of the joinrel
   * @param right right child of the joinrel
   * @return combined join filters AND'd together
   */
  private RexNode combineJoinFilters(JoinRel joinRel, RelNode left, RelNode right) {
    RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
    JoinRelType joinType = joinRel.getJoinType();

    // first need to adjust the RexInputs of the right child, since
    // those need to shift over to the right
    RexNode rightFilter = null;
    if (canCombine(right, joinType.generatesNullsOnRight())) {
      MultiJoinRel multiJoin = (MultiJoinRel) right;
      rightFilter = shiftRightFilter(joinRel, left, multiJoin, multiJoin.getJoinFilter());
    }

    // AND the join condition if this isn't a left or right outer join;
    // in those cases, the outer join condition is already tracked
    // separately
    RexNode newFilter = null;
    if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) {
      newFilter = joinRel.getCondition();
    }
    if (canCombine(left, joinType.generatesNullsOnLeft())) {
      RexNode leftFilter = ((MultiJoinRel) left).getJoinFilter();
      newFilter = RelOptUtil.andJoinFilters(rexBuilder, newFilter, leftFilter);
    }
    newFilter = RelOptUtil.andJoinFilters(rexBuilder, newFilter, rightFilter);

    return newFilter;
  }
Пример #2
0
 /**
  * Converts a relational expression to a form where {@link org.eigenbase.rel.JoinRel}s are as
  * close to leaves as possible.
  */
 public static RelNode toLeafJoinForm(RelNode rel) {
   final HepProgramBuilder programBuilder = new HepProgramBuilder();
   programBuilder.addRuleInstance(PullUpProjectsAboveJoinRule.instanceRightProjectChild);
   programBuilder.addRuleInstance(PullUpProjectsAboveJoinRule.instanceLeftProjectChild);
   final HepPlanner planner = new HepPlanner(programBuilder.createProgram());
   planner.setRoot(rel);
   System.out.println(
       RelOptUtil.dumpPlan("before", rel, false, SqlExplainLevel.DIGEST_ATTRIBUTES));
   final RelNode rel2 = planner.findBestExp();
   System.out.println(
       RelOptUtil.dumpPlan("after", rel2, false, SqlExplainLevel.DIGEST_ATTRIBUTES));
   return rel2;
 }
Пример #3
0
  public void onMatch(RelOptRuleCall call) {
    assert matches(call);
    final JoinRel join = (JoinRel) call.rels[0];
    final List<Integer> leftKeys = new ArrayList<Integer>();
    final List<Integer> rightKeys = new ArrayList<Integer>();
    RelNode right = join.getRight();
    final RelNode left = join.getLeft();
    RexNode remainingCondition =
        RelOptUtil.splitJoinCondition(left, right, join.getCondition(), leftKeys, rightKeys);
    assert leftKeys.size() == rightKeys.size();
    final List<CorrelatorRel.Correlation> correlationList =
        new ArrayList<CorrelatorRel.Correlation>();
    if (leftKeys.size() > 0) {
      final RelOptCluster cluster = join.getCluster();
      final RexBuilder rexBuilder = cluster.getRexBuilder();
      int k = 0;
      RexNode condition = null;
      for (Integer leftKey : leftKeys) {
        Integer rightKey = rightKeys.get(k++);
        final String dyn_inIdStr = cluster.getQuery().createCorrel();
        final int dyn_inId = RelOptQuery.getCorrelOrdinal(dyn_inIdStr);

        // Create correlation to say 'each row, set variable #id
        // to the value of column #leftKey'.
        correlationList.add(new CorrelatorRel.Correlation(dyn_inId, leftKey));
        condition =
            RelOptUtil.andJoinFilters(
                rexBuilder,
                condition,
                rexBuilder.makeCall(
                    SqlStdOperatorTable.equalsOperator,
                    rexBuilder.makeInputRef(
                        right.getRowType().getFieldList().get(rightKey).getType(), rightKey),
                    rexBuilder.makeCorrel(
                        left.getRowType().getFieldList().get(leftKey).getType(), dyn_inIdStr)));
      }
      right = CalcRel.createFilter(right, condition);
    }
    RelNode newRel =
        new CorrelatorRel(
            join.getCluster(),
            left,
            right,
            remainingCondition,
            correlationList,
            join.getJoinType());
    call.transformTo(newRel);
  }
  public void visit(RelNode rel, int ordinal, RelNode parent) {
    // REVIEW: SWZ: 1/31/06: We assume that any special RelNodes, such
    // as the VolcanoPlanner's RelSubset always have a full complement
    // of traits and that they either appear as registered or do nothing
    // when childrenAccept is called on them.

    if (planner.isRegistered(rel)) {
      return;
    }

    RelTraitSet relTraits = rel.getTraitSet();
    for (int i = 0; i < baseTraits.size(); i++) {
      if (i >= relTraits.size()) {
        // Copy traits that the new rel doesn't know about.
        Util.discard(RelOptUtil.addTrait(rel, baseTraits.getTrait(i)));

        // FIXME: Return the new rel. We can no longer traits in-place,
        //   because rels and traits are immutable.
        throw new AssertionError();
      } else {
        // Verify that the traits are from the same RelTraitDef
        assert relTraits.getTrait(i).getTraitDef() == baseTraits.getTrait(i).getTraitDef();
      }
    }

    rel.childrenAccept(this);
  }
 public void onMatch(RelOptRuleCall call) {
   UnionRel union = call.rel(0);
   if (union.all) {
     return; // nothing to do
   }
   UnionRel unionAll = new UnionRel(union.getCluster(), union.getInputs(), true);
   call.transformTo(RelOptUtil.createDistinctRel(unionAll));
 }
Пример #6
0
 /**
  * Converts a relational expression to a form where {@link org.eigenbase.rel.JoinRel}s are as
  * close to leaves as possible.
  */
 public static RelNode toLeafJoinForm(RelNode rel) {
   HepProgram program =
       HepProgram.builder()
           .addRuleInstance(PullUpProjectsAboveJoinRule.RIGHT_PROJECT)
           .addRuleInstance(PullUpProjectsAboveJoinRule.LEFT_PROJECT)
           .build();
   final HepPlanner planner =
       new HepPlanner(
           program, //
           rel.getCluster().getPlanner().getContext());
   planner.setRoot(rel);
   System.out.println(
       RelOptUtil.dumpPlan("before", rel, false, SqlExplainLevel.DIGEST_ATTRIBUTES));
   final RelNode rel2 = planner.findBestExp();
   System.out.println(
       RelOptUtil.dumpPlan("after", rel2, false, SqlExplainLevel.DIGEST_ATTRIBUTES));
   return rel2;
 }
 /** Splits a condition into conjunctions that do or do not intersect with a given bit set. */
 static void split(
     RexNode condition, BitSet bitSet, List<RexNode> intersecting, List<RexNode> nonIntersecting) {
   for (RexNode node : RelOptUtil.conjunctions(condition)) {
     BitSet inputBitSet = RelOptUtil.InputFinder.bits(node);
     if (bitSet.intersects(inputBitSet)) {
       intersecting.add(node);
     } else {
       nonIntersecting.add(node);
     }
   }
 }
Пример #8
0
  /**
   * Analyzes a rex predicate.
   *
   * @param rexPredicate predicate to be analyzed
   * @return a list of SargBindings contained in the input rex predicate
   */
  public List<SargBinding> analyzeAll(RexNode rexPredicate) {
    sargBindingList = new ArrayList<SargBinding>();
    sarg2RexMap = new HashMap<SargExpr, RexNode>();
    nonSargFilterList = new ArrayList<RexNode>();

    // Flatten out the RexNode tree into a list of terms that
    // are AND'ed together
    final List<RexNode> rexCFList = RelOptUtil.conjunctions(rexPredicate);

    // In simple mode, each input ref can only be referenced once, so
    // keep a list of them.  We also only allow one non-point expression.
    List<Integer> boundRefList = new ArrayList<Integer>();
    boolean rangeFound = false;

    for (RexNode rexPred : rexCFList) {
      final SargBinding sargBinding = analyze(rexPred);
      if (sargBinding != null) {
        if (simpleMode) {
          RexInputRef inputRef = sargBinding.getInputRef();
          if (boundRefList.contains(inputRef.getIndex())) {
            nonSargFilterList.add(rexPred);
            continue;
          } else {
            boundRefList.add(inputRef.getIndex());
          }
          SargIntervalSequence sargSeq = sargBinding.getExpr().evaluate();
          if (sargSeq.isRange()) {
            if (rangeFound) {
              nonSargFilterList.add(rexPred);
              continue;
            } else {
              rangeFound = true;
            }
          }
        }
        sargBindingList.add(sargBinding);
        sarg2RexMap.put(sargBinding.getExpr(), rexPred);
      } else {
        nonSargFilterList.add(rexPred);
      }
    }

    // Reset the state variables used during analyze, just for sanity sake.
    failed = false;
    boundInputRef = null;
    clearLeaf();

    // Combine the AND terms back together.
    recomposeConjunction();

    return sargBindingList;
  }
  /**
   * Creates new RelNodes replacing/removing the original project/row scan
   *
   * @param projectedScan new scan that is now projected
   * @param origProject original projection
   * @param needRename true if fields from the row scan need to be renamed
   * @param newProject projection that contains the new projection expressions, in the case where
   *     the original projection cannot be removed because it projects expressions
   * @return new RelNode
   */
  public RelNode createNewRelNode(
      RelNode projectedScan, ProjectRel origProject, boolean needRename, ProjectRel newProject) {
    RelNode scanRel;
    if (needRename) {
      // Replace calling convention with FENNEL_EXEC_CONVENTION
      RelTraitSet traits = RelOptUtil.clone(origProject.getTraits());
      traits.setTrait(CallingConventionTraitDef.instance, FennelRel.FENNEL_EXEC_CONVENTION);
      if (!traits.equals(projectedScan.getTraits())) {
        RelNode mergedProjectedScan = convert(projectedScan, traits);
        RelOptPlanner planner = projectedScan.getCluster().getPlanner();
        // register projectedScan == mergedProjectedScan
        // so mergedProjectedScan will have a set later on
        projectedScan = planner.ensureRegistered(mergedProjectedScan, projectedScan);
      }
      scanRel =
          new FennelRenameRel(
              origProject.getCluster(),
              projectedScan,
              RelOptUtil.getFieldNames(origProject.getRowType()),
              traits);
    } else {
      scanRel = projectedScan;
    }

    if (newProject == null) {
      return scanRel;
    } else {
      // in the case where the projection had expressions, put the
      // new, modified projection on top of the projected row scan
      return (ProjectRel)
          CalcRel.createProject(
              scanRel,
              newProject.getProjectExps(),
              RelOptUtil.getFieldNames(newProject.getRowType()));
    }
  }
Пример #10
0
 /**
  * Returns whether the type of an array of expressions is compatible with a struct type.
  *
  * @param exprs Array of expressions
  * @param type Type
  * @param fail Whether to fail if there is a mismatch
  * @return Whether every expression has the same type as the corresponding member of the struct
  *     type
  * @see RelOptUtil#eq(String, RelDataType, String, RelDataType, boolean)
  */
 public static boolean compatibleTypes(RexNode[] exprs, RelDataType type, boolean fail) {
   final RelDataTypeField[] fields = type.getFields();
   if (exprs.length != fields.length) {
     assert !fail : "rowtype mismatches expressions";
     return false;
   }
   for (int i = 0; i < fields.length; i++) {
     final RelDataType exprType = exprs[i].getType();
     final RelDataType fieldType = fields[i].getType();
     if (!RelOptUtil.eq("type1", exprType, "type2", fieldType, fail)) {
       return false;
     }
   }
   return true;
 }
Пример #11
0
    public OptiqPreparingStmt(
        CatalogReader catalogReader, RelDataTypeFactory typeFactory, Schema schema) {
      super(catalogReader);
      this.schema = schema;
      planner = new VolcanoPlanner();
      planner.addRelTraitDef(CallingConventionTraitDef.instance);
      RelOptUtil.registerAbstractRels(planner);
      planner.addRule(JavaRules.ENUMERABLE_JOIN_RULE);
      planner.addRule(JavaRules.ENUMERABLE_CALC_RULE);
      planner.addRule(JavaRules.ENUMERABLE_AGGREGATE_RULE);
      planner.addRule(JavaRules.ENUMERABLE_SORT_RULE);
      planner.addRule(JavaRules.ENUMERABLE_UNION_RULE);
      planner.addRule(JavaRules.ENUMERABLE_INTERSECT_RULE);
      planner.addRule(JavaRules.ENUMERABLE_MINUS_RULE);
      planner.addRule(TableAccessRule.instance);

      rexBuilder = new RexBuilder(typeFactory);
    }
Пример #12
0
    public void assertConvertsTo(String sql, String plan, boolean trim) {
      String sql2 = getDiffRepos().expand("sql", sql);
      RelNode rel = convertSqlToRel(sql2);

      assertTrue(rel != null);
      assertValid(rel);

      if (trim) {
        final RelFieldTrimmer trimmer = createFieldTrimmer();
        rel = trimmer.trim(rel);
        assertTrue(rel != null);
        assertValid(rel);
      }

      // NOTE jvs 28-Mar-2006:  insert leading newline so
      // that plans come out nicely stacked instead of first
      // line immediately after CDATA start
      String actual = NL + RelOptUtil.toString(rel);
      diffRepos.assertEquals("plan", plan, actual);
    }
Пример #13
0
  /**
   * Combines the post-join filters from the left and right inputs (if they are MultiJoinRels) into
   * a single AND'd filter.
   *
   * @param joinRel the original JoinRel
   * @param left left child of the JoinRel
   * @param right right child of the JoinRel
   * @return combined post-join filters AND'd together
   */
  private RexNode combinePostJoinFilters(JoinRel joinRel, RelNode left, RelNode right) {
    RexNode rightPostJoinFilter = null;
    if (right instanceof MultiJoinRel) {
      rightPostJoinFilter =
          shiftRightFilter(
              joinRel, left, (MultiJoinRel) right, ((MultiJoinRel) right).getPostJoinFilter());
    }

    RexNode leftPostJoinFilter = null;
    if (left instanceof MultiJoinRel) {
      leftPostJoinFilter = ((MultiJoinRel) left).getPostJoinFilter();
    }

    if ((leftPostJoinFilter == null) && (rightPostJoinFilter == null)) {
      return null;
    } else {
      return RelOptUtil.andJoinFilters(
          joinRel.getCluster().getRexBuilder(), leftPostJoinFilter, rightPostJoinFilter);
    }
  }
  // implement RelOptRule
  public void onMatch(RelOptRuleCall call) {
    final FilterRelBase filterRel = call.rel(0);
    final ProjectRelBase projRel = call.rel(1);

    // convert the filter to one that references the child of the project
    RexNode newCondition = RelOptUtil.pushFilterPastProject(filterRel.getCondition(), projRel);

    RelNode newFilterRel =
        filterFactory == null
            ? filterRel.copy(filterRel.getTraitSet(), projRel.getChild(), newCondition)
            : filterFactory.createFilter(projRel.getChild(), newCondition);

    RelNode newProjRel =
        projectFactory == null
            ? projRel.copy(
                projRel.getTraitSet(), newFilterRel, projRel.getProjects(), projRel.getRowType())
            : projectFactory.createProject(
                newFilterRel, projRel.getProjects(), projRel.getRowType().getFieldNames());

    call.transformTo(newProjRel);
  }
Пример #15
0
 /**
  * Returns whether the leading edge of a given array of expressions is wholly {@link RexInputRef}
  * objects with types corresponding to the underlying datatype.
  */
 public static boolean containIdentity(RexNode[] exprs, RelDataType rowType, boolean fail) {
   final RelDataTypeField[] fields = rowType.getFields();
   if (exprs.length < fields.length) {
     assert !fail : "exprs/rowType length mismatch";
     return false;
   }
   for (int i = 0; i < fields.length; i++) {
     if (!(exprs[i] instanceof RexInputRef)) {
       assert !fail : "expr[" + i + "] is not a RexInputRef";
       return false;
     }
     RexInputRef inputRef = (RexInputRef) exprs[i];
     if (inputRef.getIndex() != i) {
       assert !fail : "expr[" + i + "] has ordinal " + inputRef.getIndex();
       return false;
     }
     if (!RelOptUtil.eq("type1", exprs[i].getType(), "type2", fields[i].getType(), fail)) {
       return false;
     }
   }
   return true;
 }
 public void onMatch(RelOptRuleCall call) {
   final TableAccessRel oldRel = call.rel(0);
   RelNode newRel = oldRel.getTable().toRel(RelOptUtil.getContext(oldRel.getCluster()));
   call.transformTo(newRel);
 }
Пример #17
0
  // implement RelOptRuleCall
  public void transformTo(RelNode rel) {
    RelOptUtil.verifyTypeEquivalence(getRels()[0], rel, getRels()[0]);

    results.add(rel);
  }
  public void onMatch(RelOptRuleCall call) {
    AggregateRel aggRel = call.rel(0);
    UnionRel unionRel = call.rel(1);

    if (!unionRel.all) {
      // This transformation is only valid for UNION ALL.
      // Consider t1(i) with rows (5), (5) and t2(i) with
      // rows (5), (10), and the query
      // select sum(i) from (select i from t1) union (select i from t2).
      // The correct answer is 15.  If we apply the transformation,
      // we get
      // select sum(i) from
      // (select sum(i) as i from t1) union (select sum(i) as i from t2)
      // which yields 25 (incorrect).
      return;
    }

    RelOptCluster cluster = unionRel.getCluster();

    List<AggregateCall> transformedAggCalls =
        transformAggCalls(
            aggRel.getCluster().getTypeFactory(),
            aggRel.getGroupSet().cardinality(),
            aggRel.getAggCallList());
    if (transformedAggCalls == null) {
      // we've detected the presence of something like AVG,
      // which we can't handle
      return;
    }

    boolean anyTransformed = false;

    // create corresponding aggs on top of each union child
    List<RelNode> newUnionInputs = new ArrayList<RelNode>();
    for (RelNode input : unionRel.getInputs()) {
      boolean alreadyUnique = RelMdUtil.areColumnsDefinitelyUnique(input, aggRel.getGroupSet());

      if (alreadyUnique) {
        newUnionInputs.add(input);
      } else {
        anyTransformed = true;
        newUnionInputs.add(
            new AggregateRel(cluster, input, aggRel.getGroupSet(), aggRel.getAggCallList()));
      }
    }

    if (!anyTransformed) {
      // none of the children could benefit from the pushdown,
      // so bail out (preventing the infinite loop to which most
      // planners would succumb)
      return;
    }

    // create a new union whose children are the aggs created above
    UnionRel newUnionRel = new UnionRel(cluster, newUnionInputs, true);

    AggregateRel newTopAggRel =
        new AggregateRel(cluster, newUnionRel, aggRel.getGroupSet(), transformedAggCalls);

    // In case we transformed any COUNT (which is always NOT NULL)
    // to SUM (which is always NULLABLE), cast back to keep the
    // planner happy.
    RelNode castRel = RelOptUtil.createCastRel(newTopAggRel, aggRel.getRowType(), false);

    call.transformTo(castRel);
  }