return null;
}
AbstractPlanNode handleAggregationOperators(AbstractPlanNode root) {
boolean containsAggregateExpression = false;
HashAggregatePlanNode aggNode = null;
// String orig_root_debug = PlanNodeUtil.debug(root);
/* Check if any aggregate expressions are present */
for (ParsedSelectStmt.ParsedColInfo col : m_parsedSelect.displayColumns) {
if (col.expression.getExpressionType() == ExpressionType.AGGREGATE_SUM ||
col.expression.getExpressionType() == ExpressionType.AGGREGATE_COUNT ||
col.expression.getExpressionType() == ExpressionType.AGGREGATE_COUNT_STAR ||
col.expression.getExpressionType() == ExpressionType.AGGREGATE_MIN ||
col.expression.getExpressionType() == ExpressionType.AGGREGATE_MAX ||
col.expression.getExpressionType() == ExpressionType.AGGREGATE_AVG) {
containsAggregateExpression = true;
}
}
// "Select A from T group by A" is grouped but has no aggregate operator expressions
// Catch that case by checking the grouped flag. Probably the OutputColumn iteration
// above is unnecessary?
if (m_parsedSelect.grouped)
containsAggregateExpression = true;
if (containsAggregateExpression) {
aggNode = new HashAggregatePlanNode(m_context, getNextPlanNodeId());
for (ParsedSelectStmt.ParsedColInfo col : m_parsedSelect.groupByColumns) {
aggNode.getGroupByColumnOffsets().add(col.index);
aggNode.getGroupByColumnNames().add(col.alias);
PlanColumn groupByColumn =
root.findMatchingOutputColumn(col.tableName, col.columnName,
col.alias);
aggNode.appendGroupByColumn(groupByColumn);
}
int outputColumnIndex = 0;
for (ParsedSelectStmt.ParsedColInfo col : m_parsedSelect.displayColumns) {
AbstractExpression rootExpr = col.expression;
ExpressionType agg_expression_type = rootExpr.getExpressionType();
if (rootExpr.getExpressionType() == ExpressionType.AGGREGATE_SUM ||
rootExpr.getExpressionType() == ExpressionType.AGGREGATE_MIN ||
rootExpr.getExpressionType() == ExpressionType.AGGREGATE_MAX ||
rootExpr.getExpressionType() == ExpressionType.AGGREGATE_AVG ||
rootExpr.getExpressionType() == ExpressionType.AGGREGATE_COUNT ||
rootExpr.getExpressionType() == ExpressionType.AGGREGATE_COUNT_STAR)
{
PlanColumn aggregateColumn = null;
if (rootExpr.getLeft() instanceof TupleValueExpression)
{
TupleValueExpression nested =
(TupleValueExpression) rootExpr.getLeft();
if (((AggregateExpression)rootExpr).m_distinct) {
root = addDistinctNode(root, nested);
}
aggregateColumn =
root.findMatchingOutputColumn(nested.getTableName(),
nested.getColumnName(),
nested.getColumnAlias());
}
// count(*) hack. we're not getting AGGREGATE_COUNT_STAR
// expression types from the parsing, so we have
// to detect the null inner expression case and do the
// switcharoo ourselves.
else if (rootExpr.getExpressionType() == ExpressionType.AGGREGATE_COUNT &&
rootExpr.getLeft() == null)
{
aggregateColumn =
m_context.get(root.getOutputColumnGUIDs().get(0));
agg_expression_type = ExpressionType.AGGREGATE_COUNT_STAR;
}
else
{
throw new PlanningErrorException("Expressions in aggregates currently unsupported");
}
aggNode.getAggregateColumnGuids().add(aggregateColumn.guid());
aggNode.getAggregateColumnNames().add(aggregateColumn.getDisplayName());
aggNode.getAggregateTypes().add(agg_expression_type);
// A bit of a hack: ProjectionNodes using PlanColumns after the
// aggregate node need the output columns here to
// contain TupleValueExpressions (effectively on a temp table).
// So we construct one based on the output of the
// aggregate expression, the column alias provided by HSQL,
// and the offset into the output table schema for the
// aggregate node that we're computing.
TupleValueExpression tve = new TupleValueExpression();
// If this is an AVG, then our type should be DECIMAL
if (agg_expression_type == ExpressionType.AGGREGATE_AVG) {
tve.setValueType(VoltType.FLOAT);
tve.setValueSize(VoltType.FLOAT.getLengthInBytesForFixedTypes());
}
// Otherwise it can be whatever the rootExpression is
else {
tve.setValueType(rootExpr.getValueType());
tve.setValueSize(rootExpr.getValueSize());
}
tve.setColumnIndex(outputColumnIndex);
tve.setColumnName("");
tve.setColumnAlias(col.alias);
tve.setTableName(AGGREGATE_TEMP_TABLE);
PlanColumn colInfo = m_context.getPlanColumn(tve, col.alias);
aggNode.appendOutputColumn(colInfo);
aggNode.getAggregateOutputColumns().add(outputColumnIndex);
}
else
{
/*
* These columns are the pass through columns that are not being
* aggregated on. These are the ones from the SELECT list. They
* MUST already exist in the child node's output. Find them and
* add them to the aggregate's output.
*/
PlanColumn passThruColumn =
root.findMatchingOutputColumn(col.tableName,
col.columnName,
col.alias);
aggNode.appendOutputColumn(passThruColumn);
}
outputColumnIndex++;
}
aggNode.addAndLinkChild(root);
root = aggNode;
}
// PAVLO: Push non-AVG aggregates down into the scan for multi-partition queries
// 2012-02-15: Moved to AggregatePushdownOptimization