/** * 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; }
public ProjectRel clone() { ProjectRel clone = new ProjectRel( getCluster(), getChild().clone(), RexUtil.clone(exps), rowType, getFlags(), Collections.<RelCollation>emptyList()); clone.inheritTraitsFrom(this); return clone; }
public void onMatch(RelOptRuleCall call) { ProjectRel project = (ProjectRel) call.rels[0]; List<RexNode> expList = new ArrayList<RexNode>(Arrays.asList(project.getChildExps())); if (reduceExpressions(project, expList)) { call.transformTo( new ProjectRel( project.getCluster(), project.getChild(), expList.toArray(new RexNode[expList.size()]), project.getRowType(), ProjectRel.Flags.Boxed, Collections.<RelCollation>emptyList())); // New plan is absolutely better than old plan. call.getPlanner().setImportance(project, 0.0); } }
/** * Creates new RelNodes replacing/removing the original project/row scan * * @param projectedScan new scan that is now projected * @param origProject original projection * @param needRename true if fields from the row scan need to be renamed * @param newProject projection that contains the new projection expressions, in the case where * the original projection cannot be removed because it projects expressions * @return new RelNode */ public RelNode createNewRelNode( RelNode projectedScan, ProjectRel origProject, boolean needRename, ProjectRel newProject) { RelNode scanRel; if (needRename) { // Replace calling convention with FENNEL_EXEC_CONVENTION RelTraitSet traits = RelOptUtil.clone(origProject.getTraits()); traits.setTrait(CallingConventionTraitDef.instance, FennelRel.FENNEL_EXEC_CONVENTION); if (!traits.equals(projectedScan.getTraits())) { RelNode mergedProjectedScan = convert(projectedScan, traits); RelOptPlanner planner = projectedScan.getCluster().getPlanner(); // register projectedScan == mergedProjectedScan // so mergedProjectedScan will have a set later on projectedScan = planner.ensureRegistered(mergedProjectedScan, projectedScan); } scanRel = new FennelRenameRel( origProject.getCluster(), projectedScan, RelOptUtil.getFieldNames(origProject.getRowType()), traits); } else { scanRel = projectedScan; } if (newProject == null) { return scanRel; } else { // in the case where the projection had expressions, put the // new, modified projection on top of the projected row scan return (ProjectRel) CalcRel.createProject( scanRel, newProject.getProjectExps(), RelOptUtil.getFieldNames(newProject.getRowType())); } }
/** 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); }