示例#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);
   }
 }
示例#2
0
文件: CalcRel.java 项目: vlsi/optiq
 /**
  * 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);
   }
 }
  public Boolean areColumnsUnique(ProjectRelBase rel, BitSet columns, boolean ignoreNulls) {
    // ProjectRel maps a set of rows to a different set;
    // Without knowledge of the mapping function(whether it
    // preserves uniqueness), it is only safe to derive uniqueness
    // info from the child of a project when the mapping is f(a) => a.
    //
    // Also need to map the input column set to the corresponding child
    // references

    List<RexNode> projExprs = rel.getProjects();
    BitSet childColumns = new BitSet();
    for (int bit : BitSets.toIter(columns)) {
      RexNode projExpr = projExprs.get(bit);
      if (projExpr instanceof RexInputRef) {
        childColumns.set(((RexInputRef) projExpr).getIndex());
      } else if (projExpr instanceof RexCall && ignoreNulls) {
        // If the expression is a cast such that the types are the same
        // except for the nullability, then if we're ignoring nulls,
        // it doesn't matter whether the underlying column reference
        // is nullable.  Check that the types are the same by making a
        // nullable copy of both types and then comparing them.
        RexCall call = (RexCall) projExpr;
        if (call.getOperator() != SqlStdOperatorTable.CAST) {
          continue;
        }
        RexNode castOperand = call.getOperands().get(0);
        if (!(castOperand instanceof RexInputRef)) {
          continue;
        }
        RelDataTypeFactory typeFactory = rel.getCluster().getTypeFactory();
        RelDataType castType = typeFactory.createTypeWithNullability(projExpr.getType(), true);
        RelDataType origType = typeFactory.createTypeWithNullability(castOperand.getType(), true);
        if (castType.equals(origType)) {
          childColumns.set(((RexInputRef) castOperand).getIndex());
        }
      } else {
        // If the expression will not influence uniqueness of the
        // projection, then skip it.
        continue;
      }
    }

    // If no columns can affect uniqueness, then return unknown
    if (childColumns.cardinality() == 0) {
      return null;
    }

    return RelMetadataQuery.areColumnsUnique(rel.getChild(), childColumns, ignoreNulls);
  }
示例#4
0
  /**
   * Returns a relational expression which has the same fields as the underlying expression, but the
   * fields have different names.
   *
   * @param rel Relational expression
   * @param fieldNames Field names
   * @return Renamed relational expression
   */
  public static RelNode createRename(RelNode rel, List<String> fieldNames) {
    final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
    assert fieldNames.size() == fields.size();
    final List<Pair<RexNode, String>> refs =
        new AbstractList<Pair<RexNode, String>>() {
          public int size() {
            return fields.size();
          }

          public Pair<RexNode, String> get(int index) {
            return RexInputRef.of2(index, fields);
          }
        };
    return createProject(rel, refs, true);
  }
  /**
   * Creates projection list for scan. If the projection contains expressions, then the input
   * references from those expressions are extracted and that list of references becomes the
   * projection list.
   *
   * @param origScan row scan underneath the project
   * @param projRel ProjectRel that we will be creating the projection for
   * @param projectedColumns returns a list of the projected column ordinals, if it is possible to
   *     project
   * @param preserveExprCondition condition that identifies special expressions that should be
   *     preserved in the projection
   * @param defaultExpr expression to be used in the projection if no fields or special columns are
   *     selected
   * @param newProjList returns a new projection RelNode corresponding to a projection that now
   *     references a rowscan that is projecting the input references that were extracted from the
   *     original projection expressions; if the original expression didn't contain expressions,
   *     then this list is returned empty
   * @return true if columns in projection list from the scan need to be renamed
   */
  public boolean createProjectionList(
      FennelRel origScan,
      ProjectRel projRel,
      List<Integer> projectedColumns,
      PushProjector.ExprCondition preserveExprCondition,
      RexNode defaultExpr,
      List<ProjectRel> newProjList) {
    // REVIEW:  what about AnonFields?
    int n = projRel.getChildExps().length;
    RelDataType rowType = origScan.getRowType();
    RelDataType projType = projRel.getRowType();
    RelDataTypeField[] projFields = projType.getFields();
    List<Integer> tempProjList = new ArrayList<Integer>();
    boolean needRename = false;
    for (int i = 0; i < n; ++i) {
      RexNode exp = projRel.getChildExps()[i];
      List<String> origFieldName = new ArrayList<String>();
      Integer projIndex = mapProjCol(exp, origFieldName, rowType);
      if (projIndex == null) {
        // there are expressions in the projection; we need to extract
        // all input references and any special expressions from the
        // projection
        PushProjector pushProject =
            new PushProjector(projRel, null, origScan, preserveExprCondition);
        ProjectRel newProject = pushProject.convertProject(defaultExpr);
        if (newProject == null) {
          // can't do any further projection
          return false;
        }
        newProjList.add(newProject);

        // using the input references we just extracted, it should now
        // be possible to create a projection for the row scan
        needRename =
            createProjectionList(
                origScan,
                (ProjectRel) newProject.getChild(),
                projectedColumns,
                preserveExprCondition,
                defaultExpr,
                newProjList);
        assert (projectedColumns.size() > 0);
        return needRename;
      }
      String projFieldName = projFields[i].getName();
      if (!projFieldName.equals(origFieldName.get(0))) {
        needRename = true;
      }
      tempProjList.add(projIndex);
    }

    // now that we've determined it is possible to project, add the
    // ordinals to the return list
    projectedColumns.addAll(tempProjList);
    return needRename;
  }
 protected Integer mapFieldRef(RexNode exp, List<String> origFieldName, RelDataType rowType) {
   RexInputRef fieldAccess = (RexInputRef) exp;
   origFieldName.add(rowType.getFields()[fieldAccess.getIndex()].getName());
   return fieldAccess.getIndex();
 }
示例#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());
 }
示例#8
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());
 }