/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package com.espertech.esper.epl.core;
import com.espertech.esper.epl.expression.*;
import com.espertech.esper.epl.spec.OrderByItem;
import com.espertech.esper.epl.spec.RowLimitSpec;
import com.espertech.esper.epl.spec.SelectClauseExprCompiledSpec;
import com.espertech.esper.epl.variable.VariableService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* Factory for {@link com.espertech.esper.epl.core.OrderByProcessor} processors.
*/
public class OrderByProcessorFactoryFactory {
private static final Log log = LogFactory.getLog(OrderByProcessorFactoryFactory.class);
/**
* Returns processor for order-by clauses.
* @param selectionList is a list of select expressions
* @param groupByNodes is a list of group-by expressions
* @param orderByList is a list of order-by expressions
* @param rowLimitSpec specification for row limit, or null if no row limit is defined
* @param variableService for retrieving variable state for use with row limiting
* @param isSortUsingCollator for string value sorting using compare or Collator
* @return ordering processor instance
* @throws com.espertech.esper.epl.expression.ExprValidationException when validation of expressions fails
*/
public static OrderByProcessorFactory getProcessor(List<SelectClauseExprCompiledSpec> selectionList,
List<ExprNode> groupByNodes,
List<OrderByItem> orderByList,
RowLimitSpec rowLimitSpec,
VariableService variableService,
boolean isSortUsingCollator)
throws ExprValidationException
{
// Get the order by expression nodes
List<ExprNode> orderByNodes = new ArrayList<ExprNode>();
for(OrderByItem element : orderByList)
{
orderByNodes.add(element.getExprNode());
}
// No order-by clause
if(orderByList.isEmpty())
{
log.debug(".getProcessor Using no OrderByProcessor");
if (rowLimitSpec != null)
{
return new OrderByProcessorRowLimitFactory(rowLimitSpec, variableService);
}
return null;
}
// Determine aggregate functions used in select, if any
List<ExprAggregateNode> selectAggNodes = new LinkedList<ExprAggregateNode>();
for (SelectClauseExprCompiledSpec element : selectionList)
{
ExprAggregateNodeUtil.getAggregatesBottomUp(element.getSelectExpression(), selectAggNodes);
}
// Get all the aggregate functions occuring in the order-by clause
List<ExprAggregateNode> orderAggNodes = new LinkedList<ExprAggregateNode>();
for (ExprNode orderByNode : orderByNodes)
{
ExprAggregateNodeUtil.getAggregatesBottomUp(orderByNode, orderAggNodes);
}
validateOrderByAggregates(selectAggNodes, orderAggNodes);
// Tell the order-by processor whether to compute group-by
// keys if they are not present
boolean needsGroupByKeys = !selectionList.isEmpty() && !orderAggNodes.isEmpty();
log.debug(".getProcessor Using OrderByProcessorImpl");
OrderByProcessorFactoryImpl orderByProcessorFactory = new OrderByProcessorFactoryImpl(orderByList, groupByNodes, needsGroupByKeys, isSortUsingCollator);
if (rowLimitSpec == null)
{
return orderByProcessorFactory;
}
else
{
return new OrderByProcessorOrderedLimitFactory(orderByProcessorFactory, new OrderByProcessorRowLimitFactory(rowLimitSpec, variableService));
}
}
private static void validateOrderByAggregates(List<ExprAggregateNode> selectAggNodes,
List<ExprAggregateNode> orderAggNodes)
throws ExprValidationException
{
// Check that the order-by clause doesn't contain
// any aggregate functions not in the select expression
for(ExprAggregateNode orderAgg : orderAggNodes)
{
boolean inSelect = false;
for(ExprAggregateNode selectAgg : selectAggNodes)
{
if(ExprNodeUtility.deepEquals(selectAgg, orderAgg))
{
inSelect = true;
break;
}
}
if(!inSelect)
{
throw new ExprValidationException("Aggregate functions in the order-by clause must also occur in the select expression");
}
}
}
}