/** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link SortRel}. */ public TrimResult trimFields(SortRel sort, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) { final RelDataType rowType = sort.getRowType(); final int fieldCount = rowType.getFieldCount(); final RelCollation collation = sort.getCollation(); final RelNode input = sort.getChild(); // We use the fields used by the consumer, plus any fields used as sort // keys. BitSet inputFieldsUsed = (BitSet) fieldsUsed.clone(); for (RelFieldCollation field : collation.getFieldCollations()) { inputFieldsUsed.set(field.getFieldIndex()); } // Create input with trimmed columns. final Set<RelDataTypeField> inputExtraFields = Collections.emptySet(); TrimResult trimResult = trimChild(sort, 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 && inputMapping.isIdentity() && fieldsUsed.cardinality() == fieldCount) { return new TrimResult(sort, Mappings.createIdentity(fieldCount)); } final SortRel newSort = sort.copy(sort.getTraitSet(), newInput, RexUtil.apply(inputMapping, collation)); assert newSort.getClass() == sort.getClass(); // The result has the same mapping as the input gave us. Sometimes we // return fields that the consumer didn't ask for, because the filter // needs them for its condition. return new TrimResult(newSort, inputMapping); }
/** * Applies a mapping to a field collation. * * <p>If the field is not mapped, returns null. * * @param mapping Mapping * @param fieldCollation Field collation * @return collation with mapping applied */ public static RelFieldCollation apply( Mappings.TargetMapping mapping, RelFieldCollation fieldCollation) { final int target = mapping.getTargetOpt(fieldCollation.getFieldIndex()); if (target < 0) { return null; } return fieldCollation.copy(target); }
/** * Checks that a collection of collations is valid. * * @param rowType Row type of the relational expression * @param collationList List of collations * @param fail Whether to fail if invalid * @return Whether valid */ public static boolean isValid( RelDataType rowType, List<RelCollation> collationList, boolean fail) { final int fieldCount = rowType.getFieldCount(); for (RelCollation collation : collationList) { for (RelFieldCollation fieldCollation : collation.getFieldCollations()) { final int index = fieldCollation.getFieldIndex(); if (index < 0 || index >= fieldCount) { assert !fail; return false; } } } return true; }
/** Converts a collation to an ORDER BY item. */ public SqlNode toSql(RelFieldCollation collation) { SqlNode node = field(collation.getFieldIndex()); switch (collation.getDirection()) { case DESCENDING: case STRICTLY_DESCENDING: node = SqlStdOperatorTable.DESC.createCall(POS, node); } switch (collation.nullDirection) { case FIRST: node = SqlStdOperatorTable.NULLS_FIRST.createCall(POS, node); break; case LAST: node = SqlStdOperatorTable.NULLS_LAST.createCall(POS, node); break; } return node; }
/** * Returns a string representation of this collation, suitably terse given that it will appear in * plan traces. Examples: "[]", "[2]", "[0 DESC, 1]", "[0 DESC, 1 ASC NULLS LAST]". */ public String toString() { Iterator<RelFieldCollation> it = fieldCollations.iterator(); if (!it.hasNext()) { return "[]"; } StringBuilder sb = new StringBuilder(); sb.append('['); for (; ; ) { RelFieldCollation e = it.next(); sb.append(e.getFieldIndex()); if (e.direction != RelFieldCollation.Direction.ASCENDING || e.nullDirection != RelFieldCollation.NullDirection.UNSPECIFIED) { sb.append(' ').append(e.shortString()); } if (!it.hasNext()) { return sb.append(']').toString(); } sb.append(',').append(' '); } }