Beispiel #1
0
  /**
   * Infers predicates for an Aggregate.
   *
   * <p>Pulls up predicates that only contains references to columns in the GroupSet. For e.g.
   *
   * <pre>
   * childPullUpExprs : { a &gt; 7, b + c &lt; 10, a + e = 9}
   * groupSet         : { a, b}
   * pulledUpExprs    : { a &gt; 7}
   * </pre>
   */
  public RelOptPredicateList getPredicates(Aggregate agg) {
    RelNode child = agg.getInput();
    RelOptPredicateList childInfo = RelMetadataQuery.getPulledUpPredicates(child);

    List<RexNode> aggPullUpPredicates = new ArrayList<RexNode>();

    ImmutableBitSet groupKeys = agg.getGroupSet();
    Mapping m =
        Mappings.create(
            MappingType.PARTIAL_FUNCTION,
            child.getRowType().getFieldCount(),
            agg.getRowType().getFieldCount());

    int i = 0;
    for (int j : groupKeys) {
      m.set(j, i++);
    }

    for (RexNode r : childInfo.pulledUpPredicates) {
      ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(r);
      if (groupKeys.contains(rCols)) {
        r = r.accept(new RexPermuteInputsShuttle(m, child));
        aggPullUpPredicates.add(r);
      }
    }
    return RelOptPredicateList.of(aggPullUpPredicates);
  }
Beispiel #2
0
  /**
   * Infers predicates for a project.
   *
   * <ol>
   *   <li>create a mapping from input to projection. Map only positions that directly reference an
   *       input column.
   *   <li>Expressions that only contain above columns are retained in the Project's pullExpressions
   *       list.
   *   <li>For e.g. expression 'a + e = 9' below will not be pulled up because 'e' is not in the
   *       projection list.
   *       <pre>
   * childPullUpExprs:      {a &gt; 7, b + c &lt; 10, a + e = 9}
   * projectionExprs:       {a, b, c, e / 2}
   * projectionPullupExprs: {a &gt; 7, b + c &lt; 10}
   * </pre>
   * </ol>
   */
  public RelOptPredicateList getPredicates(Project project) {
    RelNode child = project.getInput();
    final RexBuilder rexBuilder = project.getCluster().getRexBuilder();
    RelOptPredicateList childInfo = RelMetadataQuery.getPulledUpPredicates(child);

    List<RexNode> projectPullUpPredicates = new ArrayList<RexNode>();

    ImmutableBitSet.Builder columnsMappedBuilder = ImmutableBitSet.builder();
    Mapping m =
        Mappings.create(
            MappingType.PARTIAL_FUNCTION,
            child.getRowType().getFieldCount(),
            project.getRowType().getFieldCount());

    for (Ord<RexNode> o : Ord.zip(project.getProjects())) {
      if (o.e instanceof RexInputRef) {
        int sIdx = ((RexInputRef) o.e).getIndex();
        m.set(sIdx, o.i);
        columnsMappedBuilder.set(sIdx);
      }
    }

    // Go over childPullUpPredicates. If a predicate only contains columns in
    // 'columnsMapped' construct a new predicate based on mapping.
    final ImmutableBitSet columnsMapped = columnsMappedBuilder.build();
    for (RexNode r : childInfo.pulledUpPredicates) {
      ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(r);
      if (columnsMapped.contains(rCols)) {
        r = r.accept(new RexPermuteInputsShuttle(m, child));
        projectPullUpPredicates.add(r);
      }
    }

    // Project can also generate constants. We need to include them.
    for (Ord<RexNode> expr : Ord.zip(project.getProjects())) {
      if (RexLiteral.isNullLiteral(expr.e)) {
        projectPullUpPredicates.add(
            rexBuilder.makeCall(
                SqlStdOperatorTable.IS_NULL, rexBuilder.makeInputRef(project, expr.i)));
      } else if (RexUtil.isConstant(expr.e)) {
        final List<RexNode> args =
            ImmutableList.of(rexBuilder.makeInputRef(project, expr.i), expr.e);
        final SqlOperator op =
            args.get(0).getType().isNullable() || args.get(1).getType().isNullable()
                ? SqlStdOperatorTable.IS_NOT_DISTINCT_FROM
                : SqlStdOperatorTable.EQUALS;
        projectPullUpPredicates.add(rexBuilder.makeCall(op, args));
      }
    }
    return RelOptPredicateList.of(projectPullUpPredicates);
  }
Beispiel #3
0
 private void infer(
     RexNode predicates,
     Set<String> allExprsDigests,
     List<RexNode> inferedPredicates,
     boolean includeEqualityInference,
     ImmutableBitSet inferringFields) {
   for (RexNode r : RelOptUtil.conjunctions(predicates)) {
     if (!includeEqualityInference && equalityPredicates.contains(r.toString())) {
       continue;
     }
     for (Mapping m : mappings(r)) {
       RexNode tr =
           r.accept(new RexPermuteInputsShuttle(m, joinRel.getInput(0), joinRel.getInput(1)));
       if (inferringFields.contains(RelOptUtil.InputFinder.bits(tr))
           && !allExprsDigests.contains(tr.toString())
           && !isAlwaysTrue(tr)) {
         inferedPredicates.add(tr);
         allExprsDigests.add(tr.toString());
       }
     }
   }
 }
Beispiel #4
0
    /**
     * The PullUp Strategy is sound but not complete.
     *
     * <ol>
     *   <li>We only pullUp inferred predicates for now. Pulling up existing predicates causes an
     *       explosion of duplicates. The existing predicates are pushed back down as new
     *       predicates. Once we have rules to eliminate duplicate Filter conditions, we should
     *       pullUp all predicates.
     *   <li>For Left Outer: we infer new predicates from the left and set them as applicable on the
     *       Right side. No predicates are pulledUp.
     *   <li>Right Outer Joins are handled in an analogous manner.
     *   <li>For Full Outer Joins no predicates are pulledUp or inferred.
     * </ol>
     */
    public RelOptPredicateList inferPredicates(boolean includeEqualityInference) {
      List<RexNode> inferredPredicates = new ArrayList<RexNode>();
      Set<String> allExprsDigests = new HashSet<String>(this.allExprsDigests);
      final JoinRelType joinType = joinRel.getJoinType();
      switch (joinType) {
        case INNER:
        case LEFT:
          infer(
              leftChildPredicates,
              allExprsDigests,
              inferredPredicates,
              includeEqualityInference,
              joinType == JoinRelType.LEFT ? rightFieldsBitSet : allFieldsBitSet);
          break;
      }
      switch (joinType) {
        case INNER:
        case RIGHT:
          infer(
              rightChildPredicates,
              allExprsDigests,
              inferredPredicates,
              includeEqualityInference,
              joinType == JoinRelType.RIGHT ? leftFieldsBitSet : allFieldsBitSet);
          break;
      }

      Mappings.TargetMapping rightMapping =
          Mappings.createShiftMapping(
              nSysFields + nFieldsLeft + nFieldsRight, 0, nSysFields + nFieldsLeft, nFieldsRight);
      final RexPermuteInputsShuttle rightPermute =
          new RexPermuteInputsShuttle(rightMapping, joinRel);
      Mappings.TargetMapping leftMapping =
          Mappings.createShiftMapping(nSysFields + nFieldsLeft, 0, nSysFields, nFieldsLeft);
      final RexPermuteInputsShuttle leftPermute = new RexPermuteInputsShuttle(leftMapping, joinRel);

      List<RexNode> leftInferredPredicates = new ArrayList<RexNode>();
      List<RexNode> rightInferredPredicates = new ArrayList<RexNode>();

      for (RexNode iP : inferredPredicates) {
        ImmutableBitSet iPBitSet = RelOptUtil.InputFinder.bits(iP);
        if (leftFieldsBitSet.contains(iPBitSet)) {
          leftInferredPredicates.add(iP.accept(leftPermute));
        } else if (rightFieldsBitSet.contains(iPBitSet)) {
          rightInferredPredicates.add(iP.accept(rightPermute));
        }
      }

      switch (joinType) {
        case INNER:
          Iterable<RexNode> pulledUpPredicates;
          if (isSemiJoin) {
            pulledUpPredicates =
                Iterables.concat(
                    RelOptUtil.conjunctions(leftChildPredicates), leftInferredPredicates);
          } else {
            pulledUpPredicates =
                Iterables.concat(
                    RelOptUtil.conjunctions(leftChildPredicates),
                    RelOptUtil.conjunctions(rightChildPredicates),
                    RelOptUtil.conjunctions(joinRel.getCondition()),
                    inferredPredicates);
          }
          return RelOptPredicateList.of(
              pulledUpPredicates, leftInferredPredicates, rightInferredPredicates);
        case LEFT:
          return RelOptPredicateList.of(
              RelOptUtil.conjunctions(leftChildPredicates),
              leftInferredPredicates,
              rightInferredPredicates);
        case RIGHT:
          return RelOptPredicateList.of(
              RelOptUtil.conjunctions(rightChildPredicates), inferredPredicates, EMPTY_LIST);
        default:
          assert inferredPredicates.size() == 0;
          return RelOptPredicateList.EMPTY;
      }
    }
Beispiel #5
0
    // We create the join predicate info object. The object contains the join condition,
    // split accordingly. If the join condition is not part of the equi-join predicate,
    // the returned object will be typed as SQLKind.OTHER.
    private static JoinLeafPredicateInfo constructJoinLeafPredicateInfo(
        List<RelNode> inputs, List<RelDataTypeField> systemFieldList, RexNode pe)
        throws CalciteSemanticException {
      JoinLeafPredicateInfo jlpi = null;
      List<Integer> filterNulls = new ArrayList<Integer>();
      List<List<RexNode>> joinExprs = new ArrayList<List<RexNode>>();
      for (int i = 0; i < inputs.size(); i++) {
        joinExprs.add(new ArrayList<RexNode>());
      }

      // 1. Split leaf join predicate to expressions from left, right
      RexNode otherConditions =
          HiveRelOptUtil.splitHiveJoinCondition(
              systemFieldList, inputs, pe, joinExprs, filterNulls, null);

      if (otherConditions.isAlwaysTrue()) {
        // 2. Collect child projection indexes used
        List<Set<Integer>> projsJoinKeysInChildSchema = new ArrayList<Set<Integer>>();
        for (int i = 0; i < inputs.size(); i++) {
          ImmutableSet.Builder<Integer> projsFromInputJoinKeysInChildSchema =
              ImmutableSet.builder();
          InputReferencedVisitor irvLeft = new InputReferencedVisitor();
          irvLeft.apply(joinExprs.get(i));
          projsFromInputJoinKeysInChildSchema.addAll(irvLeft.inputPosReferenced);
          projsJoinKeysInChildSchema.add(projsFromInputJoinKeysInChildSchema.build());
        }

        // 3. Translate projection indexes to join schema, by adding offset.
        List<Set<Integer>> projsJoinKeysInJoinSchema = new ArrayList<Set<Integer>>();
        // The offset of the first input does not need to change.
        projsJoinKeysInJoinSchema.add(projsJoinKeysInChildSchema.get(0));
        for (int i = 1; i < inputs.size(); i++) {
          int offSet = inputs.get(i - 1).getRowType().getFieldCount();
          ImmutableSet.Builder<Integer> projsFromInputJoinKeysInJoinSchema = ImmutableSet.builder();
          for (Integer indx : projsJoinKeysInChildSchema.get(i)) {
            projsFromInputJoinKeysInJoinSchema.add(indx + offSet);
          }
          projsJoinKeysInJoinSchema.add(projsFromInputJoinKeysInJoinSchema.build());
        }

        // 4. Construct JoinLeafPredicateInfo
        jlpi =
            new JoinLeafPredicateInfo(
                pe.getKind(), joinExprs, projsJoinKeysInChildSchema, projsJoinKeysInJoinSchema);
      } else {
        // 2. Construct JoinLeafPredicateInfo
        ImmutableBitSet refCols = InputFinder.bits(pe);
        int count = 0;
        for (int i = 0; i < inputs.size(); i++) {
          final int length = inputs.get(i).getRowType().getFieldCount();
          ImmutableBitSet inputRange = ImmutableBitSet.range(count, count + length);
          if (inputRange.contains(refCols)) {
            joinExprs.get(i).add(pe);
          }
          count += length;
        }
        jlpi =
            new JoinLeafPredicateInfo(
                SqlKind.OTHER,
                joinExprs,
                new ArrayList<Set<Integer>>(),
                new ArrayList<Set<Integer>>());
      }

      return jlpi;
    }