in core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java [786:940]
public TrimResult trimFields(
Join join,
ImmutableBitSet fieldsUsed,
Set<RelDataTypeField> extraFields) {
final int fieldCount = join.getSystemFieldList().size()
+ join.getLeft().getRowType().getFieldCount()
+ join.getRight().getRowType().getFieldCount();
final RexNode conditionExpr = join.getCondition();
final RexNode matchConditionExpr = (join instanceof AsofJoin)
? ((AsofJoin) join).getMatchCondition()
: null;
final int systemFieldCount = join.getSystemFieldList().size();
// Add in fields used in the condition.
final Set<RelDataTypeField> combinedInputExtraFields =
new LinkedHashSet<>(extraFields);
RelOptUtil.InputFinder inputFinder =
new RelOptUtil.InputFinder(combinedInputExtraFields, fieldsUsed);
conditionExpr.accept(inputFinder);
if (matchConditionExpr != null) {
matchConditionExpr.accept(inputFinder);
}
final ImmutableBitSet fieldsUsedPlus = inputFinder.build();
// 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;
final List<RelNode> newInputs = new ArrayList<>(2);
final List<Mapping> inputMappings = new ArrayList<>();
final List<Integer> inputExtraFieldCounts = new ArrayList<>();
for (RelNode input : join.getInputs()) {
final RelDataType inputRowType = input.getRowType();
final int inputFieldCount = inputRowType.getFieldCount();
// Compute required mapping.
ImmutableBitSet.Builder inputFieldsUsed = ImmutableBitSet.builder();
for (int bit : 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.
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 =
RelDataTypeImpl.extra(inputRowType) == null
? Collections.emptySet()
: combinedInputExtraFields;
inputExtraFieldCounts.add(inputExtraFields.size());
TrimResult trimResult =
trimChild(join, input, inputFieldsUsed.build(), 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.INVERSE_SURJECTION,
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 result(join, Mappings.createIdentity(join.getRowType().getFieldCount()));
}
// Build new join.
final RexVisitor<RexNode> shuttle =
new RexPermuteInputsShuttle(
mapping, newInputs.get(0), newInputs.get(1));
RexNode newConditionExpr =
conditionExpr.accept(shuttle);
RexNode newMatchConditionExpr =
matchConditionExpr != null ? matchConditionExpr.accept(shuttle) : null;
relBuilder.push(newInputs.get(0));
relBuilder.push(newInputs.get(1));
switch (join.getJoinType()) {
case SEMI:
case ANTI:
// For SemiJoins and AntiJoins only map fields from the left-side
if (join.getJoinType() == JoinRelType.SEMI) {
relBuilder.semiJoin(newConditionExpr);
} else {
relBuilder.antiJoin(newConditionExpr);
}
Mapping inputMapping = inputMappings.get(0);
mapping =
Mappings.create(MappingType.INVERSE_SURJECTION,
join.getRowType().getFieldCount(),
newSystemFieldCount + inputMapping.getTargetCount());
for (int i = 0; i < newSystemFieldCount; ++i) {
mapping.set(i, i);
}
offset = systemFieldCount;
newOffset = newSystemFieldCount;
for (IntPair pair : inputMapping) {
mapping.set(pair.source + offset, pair.target + newOffset);
}
break;
case ASOF:
case LEFT_ASOF:
relBuilder.asofJoin(join.getJoinType(), newConditionExpr,
requireNonNull(newMatchConditionExpr, "newMatchConditionExpr"));
break;
default:
relBuilder.join(join.getJoinType(), newConditionExpr);
break;
}
return result(relBuilder.build(), mapping, join);
}