18 using System.Collections.Generic;
32 if (expression == null)
51 foreach (var column
in expression.SelectColumns) {
56 selectColumns.SelectAllColumnsFromAllSources();
59 selectColumns.SelectAllColumnsFromSource(column.TableName);
63 selectColumns.SelectSingleColumn(column);
74 int fsz = functionsList.Count;
75 var completeFunList =
new List<object>();
76 for (
int i = 0; i < fsz; ++i) {
77 var scol = functionsList[i];
78 completeFunList.Add(scol.Expression);
79 completeFunList.Add(scol.InternalName.Name);
82 for (
int i = 0; i < aggregateFunctions.Count; ++i) {
83 completeFunList.Add(aggregateFunctions[i]);
84 completeFunList.Add(
"HAVINGAGG_" + (i + 1));
87 int fsz2 = completeFunList.Count / 2;
89 defFunNames =
new string[fsz2];
90 for (
int i = 0; i < fsz2; ++i) {
92 defFunNames[i] = (string)completeFunList[(i * 2) + 1];
112 var groupFunName =
new string[gfsz];
113 for (
int i = 0; i < gfsz; ++i) {
115 groupFunName[i] =
"#GROUPBY-" + i;
142 public int GroupByCount {
get; set; }
148 public int FunctionCount {
get; set; }
150 public string[] FunctionNames {
get; set; }
168 var subQuerySource = (FromTableSubQuerySource) tableSource;
170 var subQueryExpr = subQuerySource.QueryExpression;
171 var subQueryFrom = subQuerySource.QueryFrom;
173 plan = PlanQuery(context, subQueryExpr, subQueryFrom, null, null);
176 throw new InvalidOperationException(
"The root node of a sub-query plan must be a subset.");
178 var subsetNode = (SubsetNode) plan;
179 subsetNode.SetAliasParentName(subQuerySource.AliasName);
181 var directSource = (FromTableDirectSource) tableSource;
182 plan = directSource.QueryPlan;
184 throw new InvalidOperationException(
String.Format(
"The type of FROM source '{0}' is not supported.", tableSource.GetType()));
187 tablePlanner.AddPlan(plan, tableSource);
196 bool allInner =
true;
197 for (
int i = 0; i < fromClause.JoinPartCount; i++) {
199 if (joinPart.JoinType !=
JoinType.Inner)
203 for (
int i = 0; i < fromClause.JoinPartCount; i++) {
204 var joinPart = fromClause.GetJoinPart(i);
207 var onExpression = joinPart.OnExpression;
212 if (searchExpression != null && onExpression != null)
216 if (joinType ==
JoinType.Inner && onExpression == null) {
221 if (onExpression == null)
222 throw new InvalidOperationException(
String.Format(
"Join of type {0} requires ON expression.", joinType));
227 tablePlanner.
JoinAt(i, joinType, onExpression);
235 var binary = (SqlBinaryExpression) havingExpression;
237 var newLeft = FilterHaving(binary.Left, aggregates, context);
238 var newRight = FilterHaving(binary.Right, aggregates, context);
243 if (havingExpression.HasAggregate(context)) {
247 aggregates.
Add(havingExpression);
249 var name =
new ObjectName(FunctionTableName,
String.Format(
"HAVINGAGG_{0}", aggregates.Count));
253 return havingExpression;
257 var groupBy = queryExpression.
GroupBy == null
258 ?
new List<SqlExpression>(0)
259 : queryExpression.
GroupBy.ToList();
260 var groupBySize = groupBy.Count;
262 expressions =
new List<SqlExpression>();
265 for (
int i = 0; i < groupBySize; i++) {
266 var expression = groupBy[i];
271 var columnName = expression.AsReferenceName();
272 if (columnName != null)
275 if (expression != null) {
276 if (expression.HasAggregate(context))
277 throw new InvalidOperationException(
String.Format(
"Aggregate expression '{0}' is not allowed in a GROUP BY clause", expression));
279 expressions.
Add(expression);
280 columnName =
new ObjectName(FunctionTableName,
String.Format(
"#GROUPBY-{0}", expressions.Count -1));
283 columnNames[i] = columnName;
290 var groupMax = queryExpression.
GroupMax;
291 if (groupMax != null) {
293 if (variable == null)
294 throw new InvalidOperationException(
String.Format(
"The GROUP MAX column '{0}' was not found.", groupMax));
304 throw new InvalidOperationException(
"Invalid use of aggregate function in select with no FROM clause");
308 int colCount = selectedColumns.Count;
309 var colNames =
new string[colCount];
313 for (
int i = 0; i < colCount; ++i) {
325 IEnumerable<SortColumn> orderBy) {
333 var resolvedColumns =
new List<SortColumn>();
334 foreach (var column
in orderBy) {
335 var resolved = column;
337 var expression = column.Expression;
342 var colRef = ((
SqlNumber) value.Value).ToInt32() - 1;
343 if (colRef >= 0 && colRef < columnCount) {
344 var funArray = columnSet.FunctionColumns.ToArray();
345 var refExp = funArray[colRef];
347 resolved =
new SortColumn(refExp.Expression, column.Ascending);
352 resolvedColumns.Add(resolved);
355 return resolvedColumns.ToArray();
359 if (queryInfo == null)
360 throw new ArgumentNullException(
"queryInfo");
362 var context = queryInfo.
Request;
365 var limit = queryInfo.
Limit;
368 var orderBy =
new List<SortColumn>();
369 if (sortColumns != null)
370 orderBy.AddRange(sortColumns);
372 return PlanQuery(context, queryExpression, queryFrom, orderBy, limit);
384 var columns = BuildSelectColumns(queryExpression, queryFrom);
387 var preparedColumns = columns.Prepare(context);
389 sortColumns = ResolveOrderByRefs(preparedColumns, sortColumns);
396 var tablePlanner = CreateTablePlanner(context, queryFrom);
404 PrepareJoins(tablePlanner, queryExpression, queryFrom, ref whereClause);
408 whereClause = PrepareSearchExpression(context, queryFrom, whereClause);
409 havingClause = PrepareSearchExpression(context, queryFrom, havingClause);
414 var extraAggregateFunctions =
new List<SqlExpression>();
415 if (havingClause != null)
416 havingClause = FilterHaving(havingClause, extraAggregateFunctions, context);
420 IList<SqlExpression> groupByFunctions;
421 var gsz = ResolveGroupBy(queryExpression, queryFrom, context, out groupByList, out groupByFunctions);
424 var groupmaxColumn = ResolveGroupMax(queryExpression, queryFrom);
434 return EvaluateToSingle(preparedColumns);
438 var node = tablePlanner.PlanSearchExpression(whereClause);
441 string[] defFunNames;
442 var fsz = MakeupFunctions(preparedColumns, extraAggregateFunctions, out defFunList, out defFunNames);
445 Columns = preparedColumns,
447 FunctionNames = defFunNames,
448 FunctionExpressions = defFunList,
450 GroupByNames = groupByList,
451 GroupByExpressions = groupByFunctions.ToArray(),
452 GroupMax = groupmaxColumn
455 node = PlanGroup(node, groupInfo);
458 var selectColumns = preparedColumns.SelectedColumns.ToList();
459 int sz = selectColumns.Count;
462 if (havingClause != null) {
465 var havingExpr = havingClause;
468 havingExpr = ReplaceAliasedVariables(havingExpr, selectColumns);
470 var source = tablePlanner.SinglePlan;
471 source.UpdatePlan(node);
472 node = tablePlanner.PlanSearchExpression(havingExpr);
482 rightComposite = PlanQuery(context, compositeExpr, compositeFrom, null, null);
487 if (doSubsetColumn) {
491 for (
int i = 0; i < sz; ++i) {
505 if (rightComposite == null && sortColumns != null)
506 node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);
509 node =
new SubsetNode(node, subsetVars, aliases);
512 if (rightComposite == null && sortColumns != null)
513 node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);
517 if (rightComposite != null) {
522 if (sortColumns != null)
523 node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);
526 if (!(node is
SubsetNode) && aliases != null) {
527 node =
new SubsetNode(node, aliases, aliases);
539 if (orderBy.Count > 0) {
540 int sz = orderBy.Count;
542 var ascendingList =
new bool[sz];
544 var functionOrders =
new List<SqlExpression>();
546 for (
int i = 0; i < sz; ++i) {
547 var column = orderBy[i];
549 ascendingList[i] = column.Ascending;
550 var v = exp.AsReferenceName();
555 throw new InvalidOperationException(
String.Format(
"Could not resolve ORDER BY column '{0}' in expression", v));
557 newV = ReplaceAliasedVariable(newV, selectedColumns);
568 exp = ReplaceAliasedVariables(exp, selectedColumns);
572 orderList[i] =
new ObjectName(FunctionTableName,
"#ORDER-" + functionOrders.Count);
573 functionOrders.Add(exp);
581 int fsz = functionOrders.Count;
584 var fnames =
new String[fsz];
585 for (
int n = 0; n < fsz; ++n) {
586 funs[n] = functionOrders[n];
587 fnames[n] =
"#ORDER-" + n;
594 var topSubsetNode = (SubsetNode)plan;
595 var mappedNames = topSubsetNode.AliasColumnNames;
600 plan =
new SortNode(plan, orderList, ascendingList);
602 plan =
new SubsetNode(plan, mappedNames, mappedNames);
607 plan =
new SortNode(plan, orderList, ascendingList);
613 plan =
new SortNode(plan, orderList, ascendingList);
622 return replacer.Visit(expression);
626 foreach (var column
in selectColumns) {
627 if (column.ResolvedName.Equals(variableName))
628 return column.InternalName;
634 #region QueryExpressionPreparer
642 this.planner = planner;
643 this.parent = parent;
644 this.context = context;
654 queryFrom.
Parent = parent;
655 var plan = planner.PlanQuery(context, queryExpression, queryFrom, null, null);
662 #region VariableReplacer
668 this.selectColumns = selectColumns;
673 return base.VisitVariableReference(reference);
678 foreach (var column
in selectColumns) {
679 if (refName.Equals(column.ResolvedName))
683 return base.VisitReference(reference);
QueryTablePlanner CreateTablePlanner(IRequest context, QueryExpressionFrom queryFrom)
void PrepareJoins(QueryTablePlanner tablePlanner, SqlQueryExpression queryExpression, QueryExpressionFrom queryFrom, ref SqlExpression searchExpression)
SqlExpression PrepareSearchExpression(IRequest context, QueryExpressionFrom queryFrom, SqlExpression expression)
PreparedQuerySelectColumns Columns
IEnumerable< SelectColumn > SelectColumns
ObjectName ReferenceName
Gets the name of the object referenced by the expression.
readonly IEnumerable< SelectColumn > selectColumns
A branch node for performing a composite function on two child nodes.
An implementation of IFromTableSource that wraps around a SqlQueryExpression as a sub-query source...
SqlExpression FindExpression(ObjectName alias)
An expression that references an object within a context.
A long string in the system.
static SqlBinaryExpression And(SqlExpression left, SqlExpression right)
JoinType
Enumerates the kind of group join in a selection query.
IFromTableSource GetTableSource(int offset)
ObjectName ResolveReference(ObjectName refName)
QuerySelectColumns BuildSelectColumns(SqlQueryExpression expression, QueryExpressionFrom queryFrom)
override SqlExpression VisitVariableReference(SqlVariableReferenceExpression reference)
bool CanPrepare(SqlExpression expression)
Verifies whether the instance of the interface can prepare the given expression.
SqlExpression Prepare(SqlExpression expression)
Returns the new translated object to be mutated from the given expression.
IEnumerable< SelectColumn > FunctionColumns
Describes the name of an object within a database.
JoinPart GetJoinPart(int offset)
Gets the descriptor of the join at the given offset.
readonly IRequest context
SqlExpression FilterHaving(SqlExpression havingExpression, IList< SqlExpression > aggregates, IRequest context)
SqlQueryExpression NextComposite
IEnumerable< SqlExpression > GroupBy
SqlExpression[] FunctionExpressions
SqlExpressionType
All the possible type of SqlExpression supported
IEnumerable< SelectColumn > SelectedColumns
A node element of a query plan tree. /summary>
int ResolveGroupBy(SqlQueryExpression queryExpression, QueryExpressionFrom queryFrom, IRequest context, out ObjectName[] columnNames, out IList< SqlExpression > expressions)
static int MakeupFunctions(PreparedQuerySelectColumns columnSet, IList< SqlExpression > aggregateFunctions, out SqlExpression[] defFunList, out string[] defFunNames)
IQueryPlanNode PlanGroup(IQueryPlanNode node, GroupInfo groupInfo)
The node for merging the child node with a set of new function columns over the entire result...
CompositeFunction CompositeFunction
static QueryExpressionFrom Create(IRequest context, SqlQueryExpression expression)
static SqlBinaryExpression Add(SqlExpression left, SqlExpression right)
IQueryPlanNode EvaluateToSingle(PreparedQuerySelectColumns columns)
static IList< SortColumn > ResolveOrderByRefs(PreparedQuerySelectColumns columnSet, IEnumerable< SortColumn > orderBy)
static SqlExpression ReplaceAliasedVariables(SqlExpression expression, IList< SelectColumn > selectedColumns)
Represents a dynamic object that encapsulates a defined SqlType and a compatible constant ISqlObject ...
An interface used to prepare a SqlExpression object.
SqlQueryExpression Expression
virtual SqlExpression Prepare(IExpressionPreparer preparer)
Represents a column selected to be in the output of a select statement.
SqlExpression Expression
Gets the expression used to select the column.
readonly QueryExpressionFrom parent
An expression that holds a constant value.
QueryExpressionPreparer(QueryPlanner planner, QueryExpressionFrom parent, IRequest context)
IEnumerable< SortColumn > SortColumns
string Name
Gets the name of the object being referenced.
ObjectName InternalName
The name of this column used internally to reference it.
SqlExpression[] GroupByExpressions
IExpressionPreparer ExpressionPreparer
static SqlReferenceExpression Reference(ObjectName objectName)
static ObjectName ReplaceAliasedVariable(ObjectName variableName, IEnumerable< SelectColumn > selectColumns)
QueryExpressionFrom Parent
ObjectName[] GroupByNames
IQueryPlanNode PlanQuery(IRequest context, SqlQueryExpression queryExpression, QueryExpressionFrom queryFrom, IList< SortColumn > sortColumns, QueryLimit limit)
static IQueryPlanNode PlanForOrderBy(IQueryPlanNode plan, IList< SortColumn > orderBy, QueryExpressionFrom queryFrom, IList< SelectColumn > selectedColumns)
readonly QueryPlanner planner
static SqlBinaryExpression Binary(SqlExpression left, SqlExpressionType expressionType, SqlExpression right)
ObjectName ResolveGroupMax(SqlQueryExpression queryExpression, QueryExpressionFrom queryFrom)
Defines the base class for instances that represent SQL expression tree nodes.
static SqlConstantExpression Constant(object value)
IQueryPlanNode PlanQuery(QueryInfo queryInfo)
Object used to represent a column in the ORDER BY clauses of a select statement.
override SqlExpression VisitReference(SqlReferenceExpression reference)
abstract SqlExpressionType ExpressionType
Gets the type code of this SQL expression.
ObjectName ResolvedName
The fully resolved name that this column is given in the resulting table.
SqlExpression HavingExpression
VariableReplacer(IEnumerable< SelectColumn > selectColumns)
A visitor for SqlExpression objects.
SqlExpression WhereExpression
An implementation of IFromTableSource that wraps around a ObjectName/ITable object.
void JoinAt(int betweenIndex, JoinType joinType, SqlExpression onExpression)