allRequiredFields, groupByPropagateFields, exprPropagateFields,
projectionInputs, projectionOutputs, consoleFields);
if (where != null) {
// Non-null filter conditions; apply the filter to all of our sources.
PlanNode filterNode = new FilterNode(where);
flowSpec.attachToLastLayer(filterNode);
}
// Add an aggregation layer, if required.
addAggregationToPlan(srcOutSymbolTable, flowSpec, groupByPropagateFields);
// Evaluate calculated-expression fields.
addExpressionsToPlan(flowSpec, exprPropagateFields, projectionInputs);
// Create the projected schema based on the symbol table returned by our source.
Schema projectedSchema = createFieldSchema(distinctFields(projectionOutputs));
ProjectionNode projectionNode = new ProjectionNode(projectionInputs, projectionOutputs);
projectionNode.setAttr(PlanNode.OUTPUT_SCHEMA_ATTR, projectedSchema);
flowSpec.attachToLastLayer(projectionNode);
if (mHaving != null) {
// Non-null HAVING conditions; apply another filter to our output.
PlanNode havingNode = new FilterNode(mHaving);
flowSpec.attachToLastLayer(havingNode);
}
return createReturnedContext(planContext, consoleFields);
}