Beispiel #1
0
 /**
  * Creates a relational expression which projects an array of expressions, and optionally
  * optimizes.
  *
  * <p>The result may not be a {@link ProjectRel}. If the projection is trivial, <code>child</code>
  * is returned directly; and future versions may return other formulations of expressions, such as
  * {@link CalcRel}.
  *
  * @param child input relational expression
  * @param exprs list of expressions for the input columns
  * @param fieldNames aliases of the expressions, or null to generate
  * @param optimize Whether to return <code>child</code> unchanged if the projections are trivial.
  */
 public static RelNode createProject(
     RelNode child, List<RexNode> exprs, List<String> fieldNames, boolean optimize) {
   final RelOptCluster cluster = child.getCluster();
   final RexProgram program =
       RexProgram.create(child.getRowType(), exprs, null, fieldNames, cluster.getRexBuilder());
   final List<RelCollation> collationList = program.getCollations(child.getCollationList());
   if (DEPRECATE_PROJECT_AND_FILTER) {
     return new CalcRel(
         cluster, child.getTraitSet(), child, program.getOutputRowType(), program, collationList);
   } else {
     final RelDataType rowType =
         RexUtil.createStructType(
             cluster.getTypeFactory(),
             exprs,
             fieldNames == null
                 ? null
                 : SqlValidatorUtil.uniquify(fieldNames, SqlValidatorUtil.F_SUGGESTER));
     if (optimize && RemoveTrivialProjectRule.isIdentity(exprs, rowType, child.getRowType())) {
       return child;
     }
     return new ProjectRel(
         cluster,
         cluster.traitSetOf(
             collationList.isEmpty() ? RelCollationImpl.EMPTY : collationList.get(0)),
         child,
         exprs,
         rowType,
         ProjectRelBase.Flags.BOXED);
   }
 }
Beispiel #2
0
 /**
  * Creates a relational expression which projects an array of expressions, and optionally
  * optimizes.
  *
  * <p>The result may not be a {@link ProjectRel}. If the projection is trivial, <code>child</code>
  * is returned directly; and future versions may return other formulations of expressions, such as
  * {@link CalcRel}.
  *
  * @param child input relational expression
  * @param exprs list of expressions for the input columns
  * @param fieldNames aliases of the expressions, or null to generate
  * @param optimize Whether to return <code>child</code> unchanged if the projections are trivial.
  */
 public static RelNode createProject(
     RelNode child, List<RexNode> exprs, List<String> fieldNames, boolean optimize) {
   final RelOptCluster cluster = child.getCluster();
   final RexProgram program =
       RexProgram.create(child.getRowType(), exprs, null, fieldNames, cluster.getRexBuilder());
   final List<RelCollation> collationList = program.getCollations(child.getCollationList());
   if (DeprecateProjectAndFilter) {
     return new CalcRel(
         cluster, child.getTraitSet(), child, program.getOutputRowType(), program, collationList);
   } else {
     final RelDataType rowType =
         RexUtil.createStructType(cluster.getTypeFactory(), exprs, fieldNames);
     if (optimize && RemoveTrivialProjectRule.isIdentity(exprs, rowType, child.getRowType())) {
       return child;
     }
     return new ProjectRel(
         cluster,
         cluster.traitSetOf(
             collationList.isEmpty() ? RelCollationImpl.EMPTY : collationList.get(0)),
         child,
         exprs,
         rowType,
         ProjectRelBase.Flags.Boxed);
   }
 }
Beispiel #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);
  }
Beispiel #4
0
 /**
  * Creates a relational expression which filters according to a given condition, returning the
  * same fields as its input.
  *
  * @param child Child relational expression
  * @param condition Condition
  * @return Relational expression
  */
 public static RelNode createFilter(RelNode child, RexNode condition) {
   if (DeprecateProjectAndFilter) {
     final RelOptCluster cluster = child.getCluster();
     RexProgramBuilder builder =
         new RexProgramBuilder(child.getRowType(), cluster.getRexBuilder());
     builder.addIdentity();
     builder.addCondition(condition);
     final RexProgram program = builder.getProgram();
     return new CalcRel(
         cluster,
         child.getTraitSet(),
         child,
         program.getOutputRowType(),
         program,
         Collections.<RelCollation>emptyList());
   } else {
     return new FilterRel(child.getCluster(), child, condition);
   }
 }
Beispiel #5
0
 /**
  * Creates a ProjectRel with no sort keys.
  *
  * @param cluster Cluster this relational expression belongs to
  * @param child input relational expression
  * @param exps set of expressions for the input columns
  * @param fieldNames aliases of the expressions
  * @param flags values as in {@link ProjectRelBase.Flags}
  */
 public ProjectRel(
     RelOptCluster cluster, RelNode child, RexNode[] exps, String[] fieldNames, int flags) {
   this(
       cluster,
       child,
       exps,
       RexUtil.createStructType(cluster.getTypeFactory(), exps, fieldNames),
       flags,
       Collections.<RelCollation>emptyList());
 }
Beispiel #6
0
  /**
   * Creates a sorter.
   *
   * @param cluster Cluster this relational expression belongs to
   * @param traits Traits
   * @param child input relational expression
   * @param collations array of sort specifications
   */
  public SortRel(
      RelOptCluster cluster,
      RelTraitSet traits,
      RelNode child,
      List<RelFieldCollation> collations) {
    super(cluster, traits, child);
    this.collations = collations;

    fieldExps = new RexNode[collations.size()];
    final RelDataTypeField[] fields = getRowType().getFields();
    for (int i = 0; i < collations.size(); ++i) {
      int iField = collations.get(i).getFieldIndex();
      fieldExps[i] = cluster.getRexBuilder().makeInputRef(fields[iField].getType(), iField);
    }
  }
Beispiel #7
0
  /**
   * Creates a sorter.
   *
   * @param cluster Cluster this relational expression belongs to
   * @param traits Traits
   * @param child input relational expression
   * @param collation array of sort specifications
   * @param offset Expression for number of rows to discard before returning first row
   * @param fetch Expression for number of rows to fetch
   */
  public SortRel(
      RelOptCluster cluster,
      RelTraitSet traits,
      RelNode child,
      RelCollation collation,
      RexNode offset,
      RexNode fetch) {
    super(cluster, traits, child);
    this.collation = collation;
    this.offset = offset;
    this.fetch = fetch;

    assert traits.containsIfApplicable(collation) : "traits=" + traits + ", collation=" + collation;
    assert !(fetch == null && offset == null && collation.getFieldCollations().isEmpty())
        : "trivial sort";
    ImmutableList.Builder<RexNode> builder = ImmutableList.builder();
    for (RelFieldCollation field : collation.getFieldCollations()) {
      int index = field.getFieldIndex();
      builder.add(cluster.getRexBuilder().makeInputRef(child, index));
    }
    fieldExps = builder.build();
  }
  private void onMatchRight(RelOptRuleCall call) {
    final JoinRelBase topJoin = call.rel(0);
    final JoinRelBase bottomJoin = call.rel(1);
    final RelNode relC = call.rel(2);
    final RelNode relA = bottomJoin.getLeft();
    final RelNode relB = bottomJoin.getRight();
    final RelOptCluster cluster = topJoin.getCluster();

    //        topJoin
    //        /     \
    //   bottomJoin  C
    //    /    \
    //   A      B

    final int aCount = relA.getRowType().getFieldCount();
    final int bCount = relB.getRowType().getFieldCount();
    final int cCount = relC.getRowType().getFieldCount();
    final BitSet bBitSet = BitSets.range(aCount, aCount + bCount);

    // becomes
    //
    //        newTopJoin
    //        /        \
    //   newBottomJoin  B
    //    /    \
    //   A      C

    // If either join is not inner, we cannot proceed.
    // (Is this too strict?)
    if (topJoin.getJoinType() != JoinRelType.INNER
        || bottomJoin.getJoinType() != JoinRelType.INNER) {
      return;
    }

    // Split the condition of topJoin into a conjunction. Each of the
    // parts that does not use columns from B can be pushed down.
    final List<RexNode> intersecting = new ArrayList<RexNode>();
    final List<RexNode> nonIntersecting = new ArrayList<RexNode>();
    split(topJoin.getCondition(), bBitSet, intersecting, nonIntersecting);

    // If there's nothing to push down, it's not worth proceeding.
    if (nonIntersecting.isEmpty()) {
      return;
    }

    // Split the condition of bottomJoin into a conjunction. Each of the
    // parts that use columns from B will need to be pulled up.
    final List<RexNode> bottomIntersecting = new ArrayList<RexNode>();
    final List<RexNode> bottomNonIntersecting = new ArrayList<RexNode>();
    split(bottomJoin.getCondition(), bBitSet, bottomIntersecting, bottomNonIntersecting);

    // target: | A       | C      |
    // source: | A       | B | C      |
    final Mappings.TargetMapping bottomMapping =
        Mappings.createShiftMapping(
            aCount + bCount + cCount, 0, 0, aCount, aCount, aCount + bCount, cCount);
    List<RexNode> newBottomList = new ArrayList<RexNode>();
    new RexPermuteInputsShuttle(bottomMapping, relA, relC)
        .visitList(nonIntersecting, newBottomList);
    final Mappings.TargetMapping bottomBottomMapping =
        Mappings.createShiftMapping(aCount + bCount, 0, 0, aCount);
    new RexPermuteInputsShuttle(bottomBottomMapping, relA, relC)
        .visitList(bottomNonIntersecting, newBottomList);
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
    final JoinRelBase newBottomJoin =
        bottomJoin.copy(
            bottomJoin.getTraitSet(), newBottomCondition, relA, relC, bottomJoin.getJoinType());

    // target: | A       | C      | B |
    // source: | A       | B | C      |
    final Mappings.TargetMapping topMapping =
        Mappings.createShiftMapping(
            aCount + bCount + cCount,
            0,
            0,
            aCount,
            aCount + cCount,
            aCount,
            bCount,
            aCount,
            aCount + bCount,
            cCount);
    List<RexNode> newTopList = new ArrayList<RexNode>();
    new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB)
        .visitList(intersecting, newTopList);
    new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB)
        .visitList(bottomIntersecting, newTopList);
    RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
    @SuppressWarnings("SuspiciousNameCombination")
    final JoinRelBase newTopJoin =
        topJoin.copy(
            topJoin.getTraitSet(), newTopCondition, newBottomJoin, relB, topJoin.getJoinType());

    assert !Mappings.isIdentity(topMapping);
    final RelNode newProject =
        RelFactories.createProject(projectFactory, newTopJoin, Mappings.asList(topMapping));

    call.transformTo(newProject);
  }
Beispiel #9
0
 /**
  * Creates a new ValuesRel. Note that tuples passed in become owned by this rel (without a deep
  * copy), so caller must not modify them after this call, otherwise bad things will happen.
  *
  * @param cluster .
  * @param rowType row type for tuples produced by this rel
  * @param tuples 2-dimensional array of tuple values to be produced; outer list contains tuples;
  *     each inner list is one tuple; all tuples must be of same length, conforming to rowType
  */
 public ValuesRel(RelOptCluster cluster, RelDataType rowType, List<List<RexLiteral>> tuples) {
   super(cluster, rowType, tuples, cluster.traitSetOf(Convention.NONE));
 }