public LogicalNode visitGroupBy(PlanContext context, Stack<Expr> stack, Aggregation aggregation)
throws PlanningException {
// Initialization Phase:
LogicalPlan plan = context.plan;
QueryBlock block = context.queryBlock;
// Normalize grouping keys and add normalized grouping keys to NamedExprManager
int groupingKeyNum = aggregation.getGroupSet()[0].getGroupingSets().length;
ExprNormalizedResult [] normalizedResults = new ExprNormalizedResult[groupingKeyNum];
for (int i = 0; i < groupingKeyNum; i++) {
Expr groupingKey = aggregation.getGroupSet()[0].getGroupingSets()[i];
normalizedResults[i] = normalizer.normalize(context, groupingKey);
}
String [] groupingKeyRefNames = new String[groupingKeyNum];
for (int i = 0; i < groupingKeyNum; i++) {
groupingKeyRefNames[i] = block.namedExprsMgr.addExpr(normalizedResults[i].baseExpr);
block.namedExprsMgr.addNamedExprArray(normalizedResults[i].aggExprs);
block.namedExprsMgr.addNamedExprArray(normalizedResults[i].scalarExprs);
}
////////////////////////////////////////////////////////
// Visit and Build Child Plan
////////////////////////////////////////////////////////
stack.push(aggregation);
LogicalNode child = visit(context, stack, aggregation.getChild());
stack.pop();
////////////////////////////////////////////////////////
GroupbyNode groupingNode = context.queryBlock.getNodeFromExpr(aggregation);
groupingNode.setChild(child);
groupingNode.setInSchema(child.getOutSchema());
// Set grouping sets
Column [] groupingColumns = new Column[aggregation.getGroupSet()[0].getGroupingSets().length];
for (int i = 0; i < groupingColumns.length; i++) {
if (block.namedExprsMgr.isEvaluated(groupingKeyRefNames[i])) {
groupingColumns[i] = block.namedExprsMgr.getTarget(groupingKeyRefNames[i]).getNamedColumn();
} else {
throw new PlanningException("Each grouping column expression must be a scalar expression.");
}
}
groupingNode.setGroupingColumns(groupingColumns);
////////////////////////////////////////////////////////
// Visit and Build Child Plan
////////////////////////////////////////////////////////
// create EvalNodes and check if each EvalNode can be evaluated here.
List<String> aggEvalNames = TUtil.newList();
List<AggregationFunctionCallEval> aggEvalNodes = TUtil.newList();
boolean includeDistinctFunction = false;
for (Iterator<NamedExpr> iterator = block.namedExprsMgr.getIteratorForUnevaluatedExprs(); iterator.hasNext();) {
NamedExpr namedExpr = iterator.next();
try {
includeDistinctFunction |= PlannerUtil.existsDistinctAggregationFunction(namedExpr.getExpr());
EvalNode evalNode = exprAnnotator.createEvalNode(context.plan, context.queryBlock, namedExpr.getExpr());
if (evalNode.getType() == EvalType.AGG_FUNCTION) {
block.namedExprsMgr.markAsEvaluated(namedExpr.getAlias(), evalNode);
aggEvalNames.add(namedExpr.getAlias());
aggEvalNodes.add((AggregationFunctionCallEval) evalNode);
}
} catch (VerifyException ve) {
}
}
// if there is at least one distinct aggregation function
groupingNode.setDistinct(includeDistinctFunction);
groupingNode.setAggFunctions(aggEvalNodes.toArray(new AggregationFunctionCallEval[aggEvalNodes.size()]));
Target [] targets = new Target[groupingKeyNum + aggEvalNames.size()];
// In target, grouping columns will be followed by aggregation evals.
//
// col1, col2, col3, sum(..), agv(..)
// ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
// grouping keys aggregation evals
// Build grouping keys
for (int i = 0; i < groupingKeyNum; i++) {
Target target = block.namedExprsMgr.getTarget(groupingNode.getGroupingColumns()[i].getQualifiedName());
targets[i] = target;
}
for (int i = 0, targetIdx = groupingKeyNum; i < aggEvalNodes.size(); i++, targetIdx++) {
targets[targetIdx] = block.namedExprsMgr.getTarget(aggEvalNames.get(i));
}
groupingNode.setTargets(targets);
block.unsetAggregationRequire();
verifyProjectedFields(block, groupingNode);
return groupingNode;
}