Example #1
0
 /**
  * Creates a relational expression which permutes the output fields of a relational expression
  * according to a permutation.
  *
  * <p>Optimizations:
  *
  * <ul>
  *   <li>If the relational expression is a {@link CalcRel} or {@link ProjectRel} which is already
  *       acting as a permutation, combines the new permutation with the old;
  *   <li>If the permutation is the identity, returns the original relational expression.
  * </ul>
  *
  * <p>If a permutation is combined with its inverse, these optimizations would combine to remove
  * them both.
  *
  * @param rel Relational expression
  * @param permutation Permutation to apply to fields
  * @param fieldNames Field names; if null, or if a particular entry is null, the name of the
  *     permuted field is used
  * @return relational expression which permutes its input fields
  */
 public static RelNode permute(RelNode rel, Permutation permutation, List<String> fieldNames) {
   if (permutation.isIdentity()) {
     return rel;
   }
   if (rel instanceof CalcRel) {
     CalcRel calcRel = (CalcRel) rel;
     Permutation permutation1 = calcRel.getProgram().getPermutation();
     if (permutation1 != null) {
       Permutation permutation2 = permutation.product(permutation1);
       return permute(rel, permutation2, null);
     }
   }
   if (rel instanceof ProjectRel) {
     Permutation permutation1 = ((ProjectRel) rel).getPermutation();
     if (permutation1 != null) {
       Permutation permutation2 = permutation.product(permutation1);
       return permute(rel, permutation2, null);
     }
   }
   final List<RelDataType> outputTypeList = new ArrayList<RelDataType>();
   final List<String> outputNameList = new ArrayList<String>();
   final List<RexNode> exprList = new ArrayList<RexNode>();
   final List<RexLocalRef> projectRefList = new ArrayList<RexLocalRef>();
   final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
   for (int i = 0; i < permutation.getTargetCount(); i++) {
     int target = permutation.getTarget(i);
     final RelDataTypeField targetField = fields.get(target);
     outputTypeList.add(targetField.getType());
     outputNameList.add(
         ((fieldNames == null) || (fieldNames.size() <= i) || (fieldNames.get(i) == null))
             ? targetField.getName()
             : fieldNames.get(i));
     exprList.add(rel.getCluster().getRexBuilder().makeInputRef(fields.get(i).getType(), i));
     final int source = permutation.getSource(i);
     projectRefList.add(new RexLocalRef(source, fields.get(source).getType()));
   }
   final RexProgram program =
       new RexProgram(
           rel.getRowType(),
           exprList,
           projectRefList,
           null,
           rel.getCluster().getTypeFactory().createStructType(outputTypeList, outputNameList));
   return new CalcRel(
       rel.getCluster(),
       rel.getTraitSet(),
       rel,
       program.getOutputRowType(),
       program,
       Collections.<RelCollation>emptyList());
 }
Example #2
0
  /**
   * Looks up a field with a given name, returning null if not found.
   *
   * @param rowType Row type
   * @param columnName Field name
   * @return Field, or null if not found
   */
  public static RelDataTypeField lookupField(
      boolean caseSensitive, final RelDataType rowType, String columnName) {
    RelDataTypeField field = rowType.getField(columnName, caseSensitive);
    if (field != null) {
      return field;
    }

    // If record type is flagged as having "any field you ask for",
    // return a type. (TODO: Better way to mark accommodating types.)
    RelDataTypeField extra = RelDataTypeImpl.extra(rowType);
    if (extra != null) {
      return new RelDataTypeFieldImpl(columnName, -1, extra.getType());
    }
    return null;
  }
Example #3
0
 public static RelDataType createTypeFromProjection(
     RelDataType type,
     List<String> columnNameList,
     RelDataTypeFactory typeFactory,
     boolean caseSensitive) {
   // If the names in columnNameList and type have case-sensitive differences,
   // the resulting type will use those from type. These are presumably more
   // canonical.
   final List<RelDataTypeField> fields = new ArrayList<RelDataTypeField>(columnNameList.size());
   for (String name : columnNameList) {
     RelDataTypeField field = type.getField(name, caseSensitive);
     fields.add(type.getFieldList().get(field.getIndex()));
   }
   return typeFactory.createStructType(fields);
 }
Example #4
0
 /**
  * Generates a cast for a row type.
  *
  * @param rexBuilder RexBuilder to use for constructing casts
  * @param lhsRowType target row type
  * @param rhsExps expressions to be cast
  * @return cast expressions
  */
 public static RexNode[] generateCastExpressions(
     RexBuilder rexBuilder, RelDataType lhsRowType, RexNode[] rhsExps) {
   RelDataTypeField[] lhsFields = lhsRowType.getFields();
   final int fieldCount = lhsFields.length;
   RexNode[] castExps = new RexNode[fieldCount];
   assert fieldCount == rhsExps.length;
   for (int i = 0; i < fieldCount; ++i) {
     RelDataTypeField lhsField = lhsFields[i];
     RelDataType lhsType = lhsField.getType();
     RelDataType rhsType = rhsExps[i].getType();
     if (lhsType.equals(rhsType)) {
       castExps[i] = rhsExps[i];
     } else {
       castExps[i] = rexBuilder.makeCast(lhsType, rhsExps[i]);
     }
   }
   return castExps;
 }
Example #5
0
    private List<RelCollation> deduceMonotonicity(SqlValidatorTable table) {
      final RelDataType rowType = table.getRowType();
      final List<RelCollation> collationList = new ArrayList<RelCollation>();

      // Deduce which fields the table is sorted on.
      int i = -1;
      for (RelDataTypeField field : rowType.getFieldList()) {
        ++i;
        final SqlMonotonicity monotonicity = table.getMonotonicity(field.getName());
        if (monotonicity != SqlMonotonicity.NOT_MONOTONIC) {
          final RelFieldCollation.Direction direction =
              monotonicity.isDecreasing()
                  ? RelFieldCollation.Direction.DESCENDING
                  : RelFieldCollation.Direction.ASCENDING;
          collationList.add(
              RelCollationImpl.of(
                  new RelFieldCollation(
                      i, direction, RelFieldCollation.NullDirection.UNSPECIFIED)));
        }
      }
      return collationList;
    }
Example #6
0
 /**
  * Trims a child relational expression, then adds back a dummy project to restore the fields that
  * were removed.
  *
  * <p>Sounds pointless? It causes unused fields to be removed further down the tree (towards the
  * leaves), but it ensure that the consuming relational expression continues to see the same
  * fields.
  *
  * @param rel Relational expression
  * @param input Input relational expression, whose fields to trim
  * @param fieldsUsed Bitmap of fields needed by the consumer
  * @return New relational expression and its field mapping
  */
 protected TrimResult trimChildRestore(
     RelNode rel, RelNode input, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
   TrimResult trimResult = trimChild(rel, input, fieldsUsed, extraFields);
   if (trimResult.right.isIdentity()) {
     return trimResult;
   }
   final RelDataType rowType = input.getRowType();
   List<RelDataTypeField> fieldList = rowType.getFieldList();
   final List<RexNode> exprList = new ArrayList<RexNode>();
   final List<String> nameList = rowType.getFieldNames();
   RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
   assert trimResult.right.getSourceCount() == fieldList.size();
   for (int i = 0; i < fieldList.size(); i++) {
     int source = trimResult.right.getTargetOpt(i);
     RelDataTypeField field = fieldList.get(i);
     exprList.add(
         source < 0
             ? rexBuilder.makeZeroLiteral(field.getType())
             : rexBuilder.makeInputRef(field.getType(), source));
   }
   RelNode project = CalcRel.createProject(trimResult.left, exprList, nameList);
   return new TrimResult(project, Mappings.createIdentity(fieldList.size()));
 }
Example #7
0
 /**
  * Creates a relational expression which projects the output fields of a relational expression
  * according to a partial mapping.
  *
  * <p>A partial mapping is weaker than a permutation: every target has one source, but a source
  * may have 0, 1 or more than one targets. Usually the result will have fewer fields than the
  * source, unless some source fields are projected multiple times.
  *
  * <p>This method could optimize the result as {@link #permute} does, but does not at present.
  *
  * @param rel Relational expression
  * @param mapping Mapping from source fields to target fields. The mapping type must obey the
  *     constaints {@link MappingType#isMandatorySource()} and {@link
  *     MappingType#isSingleSource()}, as does {@link MappingType#InverseFunction}.
  * @param fieldNames Field names; if null, or if a particular entry is null, the name of the
  *     permuted field is used
  * @return relational expression which projects a subset of the input fields
  */
 public static RelNode projectMapping(RelNode rel, Mapping mapping, List<String> fieldNames) {
   assert mapping.getMappingType().isSingleSource();
   assert mapping.getMappingType().isMandatorySource();
   if (mapping.isIdentity()) {
     return rel;
   }
   final List<RelDataType> outputTypeList = new ArrayList<RelDataType>();
   final List<String> outputNameList = new ArrayList<String>();
   final List<RexNode> exprList = new ArrayList<RexNode>();
   final List<RexLocalRef> projectRefList = new ArrayList<RexLocalRef>();
   final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
   for (int i = 0; i < fields.size(); i++) {
     final RelDataTypeField field = fields.get(i);
     exprList.add(rel.getCluster().getRexBuilder().makeInputRef(field.getType(), i));
   }
   for (int i = 0; i < mapping.getTargetCount(); i++) {
     int source = mapping.getSource(i);
     final RelDataTypeField sourceField = fields.get(source);
     outputTypeList.add(sourceField.getType());
     outputNameList.add(
         ((fieldNames == null) || (fieldNames.size() <= i) || (fieldNames.get(i) == null))
             ? sourceField.getName()
             : fieldNames.get(i));
     projectRefList.add(new RexLocalRef(source, sourceField.getType()));
   }
   final RexProgram program =
       new RexProgram(
           rel.getRowType(),
           exprList,
           projectRefList,
           null,
           rel.getCluster().getTypeFactory().createStructType(outputTypeList, outputNameList));
   return new CalcRel(
       rel.getCluster(),
       rel.getTraitSet(),
       rel,
       program.getOutputRowType(),
       program,
       Collections.<RelCollation>emptyList());
 }