/** * Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link org.eigenbase.rel.ValuesRel}. */ public TrimResult trimFields( ValuesRel values, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) { final RelDataType rowType = values.getRowType(); final int fieldCount = rowType.getFieldCount(); // If they are asking for no fields, we can't give them what they want, // because zero-column records are illegal. Give them the last field, // which is unlikely to be a system field. if (fieldsUsed.isEmpty()) { fieldsUsed = Util.bitSetBetween(fieldCount - 1, fieldCount); } // If all fields are used, return unchanged. if (fieldsUsed.equals(Util.bitSetBetween(0, fieldCount))) { Mapping mapping = Mappings.createIdentity(fieldCount); return new TrimResult(values, mapping); } List<List<RexLiteral>> newTuples = new ArrayList<List<RexLiteral>>(); for (List<RexLiteral> tuple : values.getTuples()) { List<RexLiteral> newTuple = new ArrayList<RexLiteral>(); for (int field : Util.toIter(fieldsUsed)) { newTuple.add(tuple.get(field)); } newTuples.add(newTuple); } final Mapping mapping = createMapping(fieldsUsed, fieldCount); RelDataType newRowType = values .getCluster() .getTypeFactory() .createStructType(Mappings.apply3(mapping, rowType.getFieldList())); final ValuesRel newValues = new ValuesRel(values.getCluster(), newRowType, newTuples); return new TrimResult(newValues, mapping); }
/** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link ProjectRel}. */ public TrimResult trimFields( ProjectRel project, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) { final RelDataType rowType = project.getRowType(); final int fieldCount = rowType.getFieldCount(); final RelNode input = project.getChild(); final RelDataType inputRowType = input.getRowType(); // Which fields are required from the input? BitSet inputFieldsUsed = new BitSet(inputRowType.getFieldCount()); final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<RelDataTypeField>(extraFields); RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder(inputFieldsUsed, inputExtraFields); for (Ord<RexNode> ord : Ord.zip(project.getProjects())) { if (fieldsUsed.get(ord.i)) { ord.e.accept(inputFinder); } } // Create input with trimmed columns. TrimResult trimResult = trimChild(project, 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 && fieldsUsed.cardinality() == fieldCount) { return new TrimResult(project, Mappings.createIdentity(fieldCount)); } // Some parts of the system can't handle rows with zero fields, so // pretend that one field is used. if (fieldsUsed.cardinality() == 0) { final Mapping mapping = Mappings.create(MappingType.InverseSurjection, fieldCount, 1); final RexLiteral expr = project.getCluster().getRexBuilder().makeExactLiteral(BigDecimal.ZERO); RelDataType newRowType = project .getCluster() .getTypeFactory() .createStructType( Collections.singletonList(expr.getType()), Collections.singletonList("DUMMY")); ProjectRel newProject = new ProjectRel( project.getCluster(), project.getCluster().traitSetOf(RelCollationImpl.EMPTY), newInput, Collections.<RexNode>singletonList(expr), newRowType, project.getFlags()); return new TrimResult(newProject, mapping); } // Build new project expressions, and populate the mapping. List<RexNode> newProjectExprList = new ArrayList<RexNode>(); final RexVisitor<RexNode> shuttle = new RexPermuteInputsShuttle(inputMapping, newInput); final Mapping mapping = Mappings.create(MappingType.InverseSurjection, fieldCount, fieldsUsed.cardinality()); for (Ord<RexNode> ord : Ord.zip(project.getProjects())) { if (fieldsUsed.get(ord.i)) { mapping.set(ord.i, newProjectExprList.size()); RexNode newProjectExpr = ord.e.accept(shuttle); newProjectExprList.add(newProjectExpr); } } final RelDataType newRowType = project .getCluster() .getTypeFactory() .createStructType(Mappings.apply3(mapping, rowType.getFieldList())); final List<RelCollation> newCollations = RexUtil.apply(inputMapping, project.getCollationList()); final RelNode newProject; if (RemoveTrivialProjectRule.isIdentity( newProjectExprList, newRowType, newInput.getRowType())) { // The new project would be the identity. It is equivalent to return // its child. newProject = newInput; } else { newProject = new ProjectRel( project.getCluster(), project .getCluster() .traitSetOf( newCollations.isEmpty() ? RelCollationImpl.EMPTY : newCollations.get(0)), newInput, newProjectExprList, newRowType, project.getFlags()); assert newProject.getClass() == project.getClass(); } return new TrimResult(newProject, mapping); }