private static IEnumerable <ByColumn> ResolveOrderByRefs(QuerySelectColumnSet columnSet, IEnumerable <ByColumn> orderBy) { // Resolve any numerical references in the ORDER BY list (eg. // '1' will be a reference to column 1. var result = new List <ByColumn>(); if (orderBy != null) { List <SelectColumn> preparedColSet = columnSet.SelectedColumns; foreach (ByColumn col in orderBy) { var byColumn = col; Expression exp = col.Expression; if (exp is ConstantExpression) { Number bnum = ((ConstantExpression)exp).Value.ToNumber(); if (bnum.Scale == 0) { int colRef = bnum.ToInt32() - 1; if (colRef >= 0 && colRef < preparedColSet.Count) { SelectColumn scol = preparedColSet[colRef]; byColumn = new ByColumn(scol.Expression, byColumn.Ascending); } } } result.Add(byColumn); } } return(result.AsReadOnly()); }
private static int ResolveGroupBy(TableSelectExpression expression, TableExpressionFromSet fromSet, IQueryContext context, out ObjectName[] groupByList, out IList <Expression> groupByFunctions) { // Any GROUP BY functions, groupByFunctions = new List <Expression>(); // Resolve the GROUP BY variable list references in this from set IList <ByColumn> groupListIn = expression.GroupBy; int gsz = groupListIn.Count; groupByList = new ObjectName[gsz]; for (int i = 0; i < gsz; ++i) { ByColumn byColumn = groupListIn[i]; Expression exp = byColumn.Expression; // Prepare the group by expression exp.Prepare(fromSet.ExpressionQualifier); // Is the group by variable a complex expression? ObjectName v = exp.AsVariable(); Expression groupByExpression; if (v == null) { groupByExpression = exp; } else { // Can we dereference the variable to an expression in the SELECT? groupByExpression = fromSet.DereferenceAssignment(v); } if (groupByExpression != null) { if (groupByExpression.HasAggregateFunction(context)) { throw new ApplicationException("Aggregate expression '" + groupByExpression + "' is not allowed in GROUP BY clause."); } // Complex expression so add this to the function list. int groupByFunNum = groupByFunctions.Count; groupByFunctions.Add(groupByExpression); v = new ObjectName(GroupByFunctionTable, "#GROUPBY-" + groupByFunNum); } groupByList[i] = v; } return(gsz); }
/// <summary> /// Plans an ORDER BY set. /// </summary> /// <param name="plan"></param> /// <param name="orderBy"></param> /// <param name="fromSet"></param> /// <param name="selectedColumns"></param> /// <remarks> /// This is given its own function because we may want to plan /// this at the end of a number of composite functions. /// </remarks> /// <returns></returns> private static IQueryPlanNode PlanForOrderBy(IQueryPlanNode plan, IList <ByColumn> orderBy, TableExpressionFromSet fromSet, IList <SelectColumn> selectedColumns) { var functionTable = new ObjectName("FUNCTIONTABLE"); // 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 <Expression>(); for (int i = 0; i < sz; ++i) { ByColumn column = orderBy[i]; Expression exp = column.Expression; ascendingList[i] = column.Ascending; ObjectName v = exp.AsVariable(); if (v != null) { ObjectName newV = fromSet.ResolveReference(v); if (newV == null) { throw new ApplicationException("Can not resolve ORDER BY variable: " + v); } newV = SubstituteAliasedVariable(newV, selectedColumns); orderList[i] = newV; } else { // Otherwise we must be ordering by an expression such as // '0 - a'. // Resolve the expression, exp = exp.Prepare(fromSet.ExpressionQualifier); // Make sure we substitute any aliased columns in the order by // columns. exp = SubstituteAliasedVariables(exp, selectedColumns); // The new ordering functions are called 'FUNCTIONTABLE.#ORDER-n' // where n is the number of the ordering expression. orderList[i] = new ObjectName(functionTable, "#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 Expression[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 QueryPlan.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; ObjectName[] mappedNames = topSubsetNode.NewColumnNames; // 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); }