Exemple #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 (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);
   }
 }
Exemple #2
0
  /**
   * Applies a mapping to a collation list.
   *
   * @param mapping Mapping
   * @param collationList Collation list
   * @return collation list with mapping applied to each field
   */
  public static List<RelCollation> apply(
      Mappings.TargetMapping mapping, List<RelCollation> collationList) {
    final List<RelCollation> newCollationList = new ArrayList<RelCollation>();
    for (RelCollation collation : collationList) {
      final List<RelFieldCollation> newFieldCollationList = new ArrayList<RelFieldCollation>();
      for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
        final RelFieldCollation newFieldCollation = apply(mapping, fieldCollation);
        if (newFieldCollation == null) {
          // This field is not mapped. Stop here. The leading edge
          // of the collation is still valid (although it's useless
          // if it's empty).
          break;
        }
        newFieldCollationList.add(newFieldCollation);
      }
      // Truncation to collations to their leading edge creates empty
      // and duplicate collations. Ignore these.
      if (!newFieldCollationList.isEmpty()) {
        final RelCollationImpl newCollation = new RelCollationImpl(newFieldCollationList);
        if (!newCollationList.contains(newCollation)) {
          newCollationList.add(newCollation);
        }
      }
    }

    // REVIEW: There might be redundant collations in the list. For example,
    // in {(x), (x, y)}, (x) is redundant because it is a leading edge of
    // another collation in the list. Could remove redundant collations.

    return newCollationList;
  }
Exemple #3
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);
   }
 }
Exemple #4
0
  /**
   * Creates an OR expression from a list of RexNodes
   *
   * @param rexList list of RexNodes
   * @return OR'd expression
   */
  public static RexNode orRexNodeList(RexBuilder rexBuilder, List<RexNode> rexList) {
    if (rexList.isEmpty()) {
      return null;
    }

    RexNode orExpr = rexList.get(rexList.size() - 1);
    for (int i = rexList.size() - 2; i >= 0; i--) {
      orExpr = rexBuilder.makeCall(SqlStdOperatorTable.orOperator, rexList.get(i), orExpr);
    }
    return orExpr;
  }
Exemple #5
0
  /**
   * Creates an AND expression from a list of RexNodes
   *
   * @param rexList list of RexNodes
   * @return AND'd expression
   */
  public static RexNode andRexNodeList(RexBuilder rexBuilder, List<RexNode> rexList) {
    if (rexList.isEmpty()) {
      return null;
    }

    // create a right-deep tree to allow short-circuiting during
    // expression evaluation
    RexNode andExpr = rexList.get(rexList.size() - 1);
    for (int i = rexList.size() - 2; i >= 0; i--) {
      andExpr = rexBuilder.makeCall(SqlStdOperatorTable.andOperator, rexList.get(i), andExpr);
    }
    return andExpr;
  }
Exemple #6
0
  /** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link ProjectRel}. */
  public TrimResult trimFields(
      ProjectRel project, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = project.getRowType();
    final int fieldCount = rowType.getFieldCount();
    final RelNode input = project.getChild();
    final RelDataType inputRowType = input.getRowType();

    // Which fields are required from the input?
    BitSet inputFieldsUsed = new BitSet(inputRowType.getFieldCount());
    final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<RelDataTypeField>(extraFields);
    RelOptUtil.InputFinder inputFinder =
        new RelOptUtil.InputFinder(inputFieldsUsed, inputExtraFields);
    for (Ord<RexNode> ord : Ord.zip(project.getProjects())) {
      if (fieldsUsed.get(ord.i)) {
        ord.e.accept(inputFinder);
      }
    }

    // Create input with trimmed columns.
    TrimResult trimResult = trimChild(project, input, inputFieldsUsed, inputExtraFields);
    RelNode newInput = trimResult.left;
    final Mapping inputMapping = trimResult.right;

    // If the input is unchanged, and we need to project all columns,
    // there's nothing we can do.
    if (newInput == input && fieldsUsed.cardinality() == fieldCount) {
      return new TrimResult(project, Mappings.createIdentity(fieldCount));
    }

    // Some parts of the system can't handle rows with zero fields, so
    // pretend that one field is used.
    if (fieldsUsed.cardinality() == 0) {
      final Mapping mapping = Mappings.create(MappingType.InverseSurjection, fieldCount, 1);
      final RexLiteral expr =
          project.getCluster().getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
      RelDataType newRowType =
          project
              .getCluster()
              .getTypeFactory()
              .createStructType(
                  Collections.singletonList(expr.getType()), Collections.singletonList("DUMMY"));
      ProjectRel newProject =
          new ProjectRel(
              project.getCluster(),
              project.getCluster().traitSetOf(RelCollationImpl.EMPTY),
              newInput,
              Collections.<RexNode>singletonList(expr),
              newRowType,
              project.getFlags());
      return new TrimResult(newProject, mapping);
    }

    // Build new project expressions, and populate the mapping.
    List<RexNode> newProjectExprList = new ArrayList<RexNode>();
    final RexVisitor<RexNode> shuttle = new RexPermuteInputsShuttle(inputMapping, newInput);
    final Mapping mapping =
        Mappings.create(MappingType.InverseSurjection, fieldCount, fieldsUsed.cardinality());
    for (Ord<RexNode> ord : Ord.zip(project.getProjects())) {
      if (fieldsUsed.get(ord.i)) {
        mapping.set(ord.i, newProjectExprList.size());
        RexNode newProjectExpr = ord.e.accept(shuttle);
        newProjectExprList.add(newProjectExpr);
      }
    }

    final RelDataType newRowType =
        project
            .getCluster()
            .getTypeFactory()
            .createStructType(Mappings.apply3(mapping, rowType.getFieldList()));

    final List<RelCollation> newCollations =
        RexUtil.apply(inputMapping, project.getCollationList());

    final RelNode newProject;
    if (RemoveTrivialProjectRule.isIdentity(
        newProjectExprList, newRowType, newInput.getRowType())) {
      // The new project would be the identity. It is equivalent to return
      // its child.
      newProject = newInput;
    } else {
      newProject =
          new ProjectRel(
              project.getCluster(),
              project
                  .getCluster()
                  .traitSetOf(
                      newCollations.isEmpty() ? RelCollationImpl.EMPTY : newCollations.get(0)),
              newInput,
              newProjectExprList,
              newRowType,
              project.getFlags());
      assert newProject.getClass() == project.getClass();
    }
    return new TrimResult(newProject, mapping);
  }