/**
  * Divides one mapping by another.
  *
  * <p>{@code divide(A, B)} returns a mapping C such that B . C (the mapping B followed by the
  * mapping C) is equivalent to A.
  *
  * @param mapping1 First mapping
  * @param mapping2 Second mapping
  * @return Mapping mapping3 such that mapping1 = mapping2 . mapping3
  */
 public static Mapping divide(Mapping mapping1, Mapping mapping2) {
   if (mapping1.getSourceCount() != mapping2.getSourceCount()) {
     throw new IllegalArgumentException();
   }
   Mapping remaining =
       create(
           MappingType.INVERSE_SURJECTION, mapping2.getTargetCount(), mapping1.getTargetCount());
   for (int target = 0; target < mapping1.getTargetCount(); ++target) {
     int source = mapping1.getSourceOpt(target);
     if (source >= 0) {
       int x = mapping2.getTarget(source);
       remaining.set(x, target);
     }
   }
   return remaining;
 }
 /**
  * Multiplies one mapping by another.
  *
  * <p>{@code divide(A, B)} returns a mapping C such that B . C (the mapping B followed by the
  * mapping C) is equivalent to A.
  *
  * @param mapping1 First mapping
  * @param mapping2 Second mapping
  * @return Mapping mapping3 such that mapping1 = mapping2 . mapping3
  */
 public static Mapping multiply(Mapping mapping1, Mapping mapping2) {
   if (mapping1.getTargetCount() != mapping2.getSourceCount()) {
     throw new IllegalArgumentException();
   }
   Mapping product =
       create(
           MappingType.INVERSE_SURJECTION, mapping1.getSourceCount(), mapping2.getTargetCount());
   for (int source = 0; source < mapping1.getSourceCount(); ++source) {
     int x = mapping1.getTargetOpt(source);
     if (x >= 0) {
       int target = mapping2.getTarget(x);
       product.set(source, target);
     }
   }
   return product;
 }
 /**
  * Applies a mapping to a list.
  *
  * @param mapping Mapping
  * @param list List
  * @param <T> Element type
  * @return List with elements permuted according to mapping
  */
 public static <T> List<T> apply(final Mapping mapping, final List<T> list) {
   if (mapping.getSourceCount() != list.size()) {
     // REVIEW: too strict?
     throw new IllegalArgumentException(
         "mapping source count "
             + mapping.getSourceCount()
             + " does not match list size "
             + list.size());
   }
   final int targetCount = mapping.getTargetCount();
   final List<T> list2 = new ArrayList<T>(targetCount);
   for (int target = 0; target < targetCount; ++target) {
     final int source = mapping.getSource(target);
     list2.add(list.get(source));
   }
   return list2;
 }
Ejemplo n.º 4
0
 /**
  * Invokes {@link #trimFields}, or the appropriate method for the type of the rel parameter, using
  * multi-method dispatch.
  *
  * @param rel Relational expression
  * @param fieldsUsed Bitmap of fields needed by the consumer
  * @return New relational expression and its field mapping
  */
 protected final TrimResult dispatchTrimFields(
     RelNode rel, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
   final TrimResult trimResult = trimFieldsDispatcher.invoke(rel, fieldsUsed, extraFields);
   final RelNode newRel = trimResult.left;
   final Mapping mapping = trimResult.right;
   final int fieldCount = rel.getRowType().getFieldCount();
   assert mapping.getSourceCount() == fieldCount
       : "source: " + mapping.getSourceCount() + " != " + fieldCount;
   final int newFieldCount = newRel.getRowType().getFieldCount();
   assert mapping.getTargetCount() + extraFields.size() == newFieldCount
       : "target: "
           + mapping.getTargetCount()
           + " + "
           + extraFields.size()
           + " != "
           + newFieldCount;
   if (Bug.TodoFixed) assert newFieldCount > 0 : "rel has no fields after trim: " + rel;
   if (newRel.equals(rel)) {
     return new TrimResult(rel, mapping);
   }
   return trimResult;
 }
Ejemplo n.º 5
0
  /** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link JoinRel}. */
  public TrimResult trimFields(JoinRel join, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = join.getRowType();
    final int fieldCount = rowType.getFieldCount();
    final RexNode conditionExpr = join.getCondition();
    final int systemFieldCount = join.getSystemFieldList().size();

    // Add in fields used in the condition.
    BitSet fieldsUsedPlus = (BitSet) fieldsUsed.clone();
    final Set<RelDataTypeField> combinedInputExtraFields =
        new LinkedHashSet<RelDataTypeField>(extraFields);
    RelOptUtil.InputFinder inputFinder =
        new RelOptUtil.InputFinder(fieldsUsedPlus, combinedInputExtraFields);
    conditionExpr.accept(inputFinder);

    // If no system fields are used, we can remove them.
    int systemFieldUsedCount = 0;
    for (int i = 0; i < systemFieldCount; ++i) {
      if (fieldsUsed.get(i)) {
        ++systemFieldUsedCount;
      }
    }
    final int newSystemFieldCount;
    if (systemFieldUsedCount == 0) {
      newSystemFieldCount = 0;
    } else {
      newSystemFieldCount = systemFieldCount;
    }

    int offset = systemFieldCount;
    int changeCount = 0;
    int newFieldCount = newSystemFieldCount;
    List<RelNode> newInputs = new ArrayList<RelNode>(2);
    List<Mapping> inputMappings = new ArrayList<Mapping>();
    List<Integer> inputExtraFieldCounts = new ArrayList<Integer>();
    for (RelNode input : join.getInputs()) {
      final RelDataType inputRowType = input.getRowType();
      final int inputFieldCount = inputRowType.getFieldCount();

      // Compute required mapping.
      BitSet inputFieldsUsed = new BitSet(inputFieldCount);
      for (int bit : Util.toIter(fieldsUsedPlus)) {
        if (bit >= offset && bit < offset + inputFieldCount) {
          inputFieldsUsed.set(bit - offset);
        }
      }

      // If there are system fields, we automatically use the
      // corresponding field in each input.
      if (newSystemFieldCount > 0) {
        // calling with newSystemFieldCount == 0 should be safe but hits
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6222207
        inputFieldsUsed.set(0, newSystemFieldCount);
      }

      // FIXME: We ought to collect extra fields for each input
      // individually. For now, we assume that just one input has
      // on-demand fields.
      Set<RelDataTypeField> inputExtraFields =
          input.getRowType().getField("_extra") == null
              ? Collections.<RelDataTypeField>emptySet()
              : combinedInputExtraFields;
      inputExtraFieldCounts.add(inputExtraFields.size());
      TrimResult trimResult = trimChild(join, input, inputFieldsUsed, inputExtraFields);
      newInputs.add(trimResult.left);
      if (trimResult.left != input) {
        ++changeCount;
      }

      final Mapping inputMapping = trimResult.right;
      inputMappings.add(inputMapping);

      // Move offset to point to start of next input.
      offset += inputFieldCount;
      newFieldCount += inputMapping.getTargetCount() + inputExtraFields.size();
    }

    Mapping mapping = Mappings.create(MappingType.InverseSurjection, fieldCount, newFieldCount);
    for (int i = 0; i < newSystemFieldCount; ++i) {
      mapping.set(i, i);
    }
    offset = systemFieldCount;
    int newOffset = newSystemFieldCount;
    for (int i = 0; i < inputMappings.size(); i++) {
      Mapping inputMapping = inputMappings.get(i);
      for (IntPair pair : inputMapping) {
        mapping.set(pair.source + offset, pair.target + newOffset);
      }
      offset += inputMapping.getSourceCount();
      newOffset += inputMapping.getTargetCount() + inputExtraFieldCounts.get(i);
    }

    if (changeCount == 0 && mapping.isIdentity()) {
      return new TrimResult(join, Mappings.createIdentity(fieldCount));
    }

    // Build new join.
    final RexVisitor<RexNode> shuttle =
        new RexPermuteInputsShuttle(mapping, newInputs.get(0), newInputs.get(1));
    RexNode newConditionExpr = conditionExpr.accept(shuttle);

    final JoinRel newJoin =
        join.copy(join.getTraitSet(), newConditionExpr, newInputs.get(0), newInputs.get(1));

    return new TrimResult(newJoin, mapping);
  }
 public int getTargetCount() {
   return parent.getSourceCount();
 }