private static IQueryPlanNode PlanForOrderBy(IQueryPlanNode plan, IList<SortColumn> orderBy, QueryExpressionFrom queryFrom, IList<SelectColumn> selectedColumns)
{
// Sort on the ORDER BY clause
if (orderBy.Count > 0) {
int sz = orderBy.Count;
var orderList = new ObjectName[sz];
var ascendingList = new bool[sz];
var functionOrders = new List<SqlExpression>();
for (int i = 0; i < sz; ++i) {
var column = orderBy[i];
SqlExpression exp = column.Expression;
ascendingList[i] = column.Ascending;
var v = exp.AsReferenceName();
if (v != null) {
var newV = queryFrom.ResolveReference(v);
if (newV == null)
throw new InvalidOperationException(String.Format("Could not resolve ORDER BY column '{0}' in expression", v));
newV = ReplaceAliasedVariable(newV, selectedColumns);
orderList[i] = newV;
} else {
// Otherwise we must be ordering by an expression such as
// '0 - a'.
// Resolve the expression,
exp = exp.Prepare(queryFrom.ExpressionPreparer);
// Make sure we substitute any aliased columns in the order by
// columns.
exp = ReplaceAliasedVariables(exp, selectedColumns);
// The new ordering functions are called 'FUNCTIONTABLE.#ORDER-n'
// where n is the number of the ordering expression.
orderList[i] = new ObjectName(FunctionTableName, "#ORDER-" + functionOrders.Count);
functionOrders.Add(exp);
}
}
// If there are functional orderings,
// For this we must define a new FunctionTable with the expressions,
// then order by those columns, and then use another SubsetNode
// command node.
int fsz = functionOrders.Count;
if (fsz > 0) {
var funs = new SqlExpression[fsz];
var fnames = new String[fsz];
for (int n = 0; n < fsz; ++n) {
funs[n] = functionOrders[n];
fnames[n] = "#ORDER-" + n;
}
if (plan is SubsetNode) {
// If the top plan is a SubsetNode then we use the
// information from it to create a new SubsetNode that
// doesn't include the functional orders we have attached here.
var topSubsetNode = (SubsetNode)plan;
var mappedNames = topSubsetNode.AliasColumnNames;
// Defines the sort functions
plan = new CreateFunctionsNode(plan, funs, fnames);
// Then plan the sort
plan = new SortNode(plan, orderList, ascendingList);
// Then plan the subset
plan = new SubsetNode(plan, mappedNames, mappedNames);
} else {
// Defines the sort functions
plan = new CreateFunctionsNode(plan, funs, fnames);
// Plan the sort
plan = new SortNode(plan, orderList, ascendingList);
}
} else {
// No functional orders so we only need to sort by the columns
// defined.
plan = new SortNode(plan, orderList, ascendingList);
}
}
return plan;
}