protected ProcessRow generateProcessRow(
            List<AggregateExpression> expressions,
            List<AggregateFunction> functions,
            List<Attribute> inputAttributes) {
        if (expressions.isEmpty()) {
            // Grouping only.
            return (a, b) -> {
            };
        } else {
            List<Expression> processExpressions = new ArrayList<>();
            for (int i = 0; i < expressions.size(); i++) {
                switch (expressions.get(i).mode) {
                    case Partial:
                    case Complete:
                        processExpressions.addAll(functions.get(i).updateExpressions());
                        break;
                    case PartialMerge:
                    case Final:
                        processExpressions.addAll(functions.get(i).mergeExpressions());
                }
            }
            List<Attribute> aggregationBufferSchema = flatMapToList(functions, AggregateFunction::aggBufferAttributes);
            MutableProjection updateProjection = newMutableProjection.apply(
                    processExpressions,
                    concatToList(aggregationBufferSchema, inputAttributes)).get();
            JoinedRow joinedRow = new JoinedRow();
            return (currentBuffer, row) -> {
                updateProjection.target(currentBuffer).apply(joinedRow.apply(currentBuffer, row));
            };
        }
    }
The base class of [[SortBasedAggregationIterator]] and [[TungstenAggregationIterator]].
It mainly contains two parts:
1. It initializes aggregate functions.
2. It creates two functions, `processRow` and `generateOutput` based on [[AggregateMode]] of
its aggregate functions. `processRow` is the function to handle an input. `generateOutput`
is used to generate result.
indexr-query-opt/src/main/java/org/apache/spark/sql/execution/aggregate/AggregationIterator.java