Inheritance: SingleQueryPlanNode
        protected virtual IQueryPlanNode VisitDistinct(DistinctNode node)
        {
            var child = node.Child;
            if (child != null)
                child = VisitNode(child);

            return new DistinctNode(child, node.ColumnNames);
        }
        protected virtual IQueryPlanNode VisitDistinct(DistinctNode node)
        {
            var child = node.Child;

            if (child != null)
            {
                child = VisitNode(child);
            }

            return(new DistinctNode(child, node.ColumnNames));
        }
Beispiel #3
0
        private IQueryPlanNode PlanQuery(IQueryContext context, SqlQueryExpression queryExpression,
			QueryExpressionFrom queryFrom, IList<SortColumn> sortColumns)
        {
            // ----- Resolve the SELECT list
            // If there are 0 columns selected, then we assume the result should
            // show all of the columns in the result.
            bool doSubsetColumn = (queryExpression.SelectColumns.Any());

            // What we are selecting
            var columns = BuildSelectColumns(queryExpression, queryFrom);

            // Prepare the column_set,
            var preparedColumns = columns.Prepare(context);

            sortColumns = ResolveOrderByRefs(preparedColumns, sortColumns);

            // -----

            // Set up plans for each table in the from clause of the command.  For
            // sub-queries, we recurse.

            var tablePlanner = CreateTablePlanner(context, queryFrom);

            // -----

            // The WHERE and HAVING clauses
            var whereClause = queryExpression.WhereExpression;
            var havingClause = queryExpression.HavingExpression;

            PrepareJoins(tablePlanner, queryExpression, queryFrom, ref whereClause);

            // Prepare the WHERE and HAVING clause, qualifies all variables and
            // prepares sub-queries.
            whereClause = PrepareSearchExpression(context, queryFrom, whereClause);
            havingClause = PrepareSearchExpression(context, queryFrom, havingClause);

            // Any extra Aggregate functions that are part of the HAVING clause that
            // we need to add.  This is a list of a name followed by the expression
            // that contains the aggregate function.
            var extraAggregateFunctions = new List<SqlExpression>();
            if (havingClause != null)
                havingClause = FilterHaving(havingClause, extraAggregateFunctions, context);

            // Any GROUP BY functions,
            ObjectName[] groupByList;
            IList<SqlExpression> groupByFunctions;
            var gsz = ResolveGroupBy(queryExpression, queryFrom, context, out groupByList, out groupByFunctions);

            // Resolve GROUP MAX variable to a reference in this from set
            var groupmaxColumn = ResolveGroupMax(queryExpression, queryFrom);

            // -----

            // Now all the variables should be resolved and correlated variables set
            // up as appropriate.

            // If nothing in the FROM clause then simply evaluate the result of the
            // select
            if (queryFrom.SourceCount == 0)
                return EvaluateToSingle(preparedColumns);

            // Plan the where clause.  The returned node is the plan to evaluate the
            // WHERE clause.
            var node = tablePlanner.PlanSearchExpression(whereClause);

            SqlExpression[] defFunList;
            string[] defFunNames;
            var fsz = MakeupFunctions(preparedColumns, extraAggregateFunctions, out defFunList, out defFunNames);

            var groupInfo = new GroupInfo {
                Columns = preparedColumns,
                FunctionCount = fsz,
                FunctionNames = defFunNames,
                FunctionExpressions = defFunList,
                GroupByCount = gsz,
                GroupByNames = groupByList,
                GroupByExpressions = groupByFunctions.ToArray(),
                GroupMax = groupmaxColumn
            };

            node = PlanGroup(node, groupInfo);

            // The result column list
            var selectColumns = preparedColumns.SelectedColumns.ToList();
            int sz = selectColumns.Count;

            // Evaluate the having clause if necessary
            if (havingClause != null) {
                // Before we evaluate the having expression we must substitute all the
                // aliased variables.
                var havingExpr = havingClause;

                // TODO: this requires a visitor to modify the having expression
                havingExpr = ReplaceAliasedVariables(havingExpr, selectColumns);

                var source = tablePlanner.SinglePlan;
                source.UpdatePlan(node);
                node = tablePlanner.PlanSearchExpression(havingExpr);
            }

            // Do we have a composite select expression to process?
            IQueryPlanNode rightComposite = null;
            if (queryExpression.NextComposite != null) {
                var compositeExpr = queryExpression.NextComposite;
                var compositeFrom = QueryExpressionFrom.Create(context, compositeExpr);

                // Form the right plan
                rightComposite = PlanQuery(context, compositeExpr, compositeFrom, null);
            }

            // Do we do a final subset column?
            ObjectName[] aliases = null;
            if (doSubsetColumn) {
                // Make up the lists
                var subsetVars = new ObjectName[sz];
                aliases = new ObjectName[sz];
                for (int i = 0; i < sz; ++i) {
                    SelectColumn scol = selectColumns[i];
                    subsetVars[i] = scol.InternalName;
                    aliases[i] = scol.ResolvedName;
                }

                // If we are distinct then add the DistinctNode here
                if (queryExpression.Distinct)
                    node = new DistinctNode(node, subsetVars);

                // Process the ORDER BY?
                // Note that the ORDER BY has to occur before the subset call, but
                // after the distinct because distinct can affect the ordering of the
                // result.
                if (rightComposite == null && sortColumns != null)
                    node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);

                // Rename the columns as specified in the SELECT
                node = new SubsetNode(node, subsetVars, aliases);
            } else {
                // Process the ORDER BY?
                if (rightComposite == null && sortColumns != null)
                    node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);
            }

            // Do we have a composite to merge in?
            if (rightComposite != null) {
                // For the composite
                node = new CompositeNode(node, rightComposite, queryExpression.CompositeFunction, queryExpression.IsCompositeAll);

                // Final order by?
                if (sortColumns != null)
                    node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);

                // Ensure a final subset node
                if (!(node is SubsetNode) && aliases != null) {
                    node = new SubsetNode(node, aliases, aliases);
                }
            }

            return node;
        }
Beispiel #4
0
        private IQueryPlanNode PlanQuery(IRequest context, SqlQueryExpression queryExpression,
                                         QueryExpressionFrom queryFrom, IList <SortColumn> sortColumns, QueryLimit limit)
        {
            // ----- Resolve the SELECT list
            // If there are 0 columns selected, then we assume the result should
            // show all of the columns in the result.
            bool doSubsetColumn = (queryExpression.SelectColumns.Any());

            // What we are selecting
            var columns = BuildSelectColumns(queryExpression, queryFrom);

            // Prepare the column_set,
            var preparedColumns = columns.Prepare(context);

            sortColumns = ResolveOrderByRefs(preparedColumns, sortColumns);

            // -----

            // Set up plans for each table in the from clause of the command.  For
            // sub-queries, we recurse.

            var tablePlanner = CreateTablePlanner(context, queryFrom);

            // -----

            // The WHERE and HAVING clauses
            var whereClause  = queryExpression.WhereExpression;
            var havingClause = queryExpression.HavingExpression;

            PrepareJoins(tablePlanner, queryExpression, queryFrom, ref whereClause);

            // Prepare the WHERE and HAVING clause, qualifies all variables and
            // prepares sub-queries.
            whereClause  = PrepareSearchExpression(context, queryFrom, whereClause);
            havingClause = PrepareSearchExpression(context, queryFrom, havingClause);

            // Any extra Aggregate functions that are part of the HAVING clause that
            // we need to add.  This is a list of a name followed by the expression
            // that contains the aggregate function.
            var extraAggregateFunctions = new List <SqlExpression>();

            if (havingClause != null)
            {
                havingClause = FilterHaving(havingClause, extraAggregateFunctions, context);
            }

            // Any GROUP BY functions,
            ObjectName[]          groupByList;
            IList <SqlExpression> groupByFunctions;
            var gsz = ResolveGroupBy(queryExpression, queryFrom, context, out groupByList, out groupByFunctions);

            // Resolve GROUP MAX variable to a reference in this from set
            var groupmaxColumn = ResolveGroupMax(queryExpression, queryFrom);

            // -----

            // Now all the variables should be resolved and correlated variables set
            // up as appropriate.

            // If nothing in the FROM clause then simply evaluate the result of the
            // select
            if (queryFrom.SourceCount == 0)
            {
                return(EvaluateToSingle(preparedColumns));
            }

            // Plan the where clause.  The returned node is the plan to evaluate the
            // WHERE clause.
            var node = tablePlanner.PlanSearchExpression(whereClause);

            SqlExpression[] defFunList;
            string[]        defFunNames;
            var             fsz = MakeupFunctions(preparedColumns, extraAggregateFunctions, out defFunList, out defFunNames);

            var groupInfo = new GroupInfo {
                Columns             = preparedColumns,
                FunctionCount       = fsz,
                FunctionNames       = defFunNames,
                FunctionExpressions = defFunList,
                GroupByCount        = gsz,
                GroupByNames        = groupByList,
                GroupByExpressions  = groupByFunctions.ToArray(),
                GroupMax            = groupmaxColumn
            };

            node = PlanGroup(node, groupInfo);

            // The result column list
            var selectColumns = preparedColumns.SelectedColumns.ToList();
            int sz            = selectColumns.Count;

            // Evaluate the having clause if necessary
            if (havingClause != null)
            {
                // Before we evaluate the having expression we must substitute all the
                // aliased variables.
                var havingExpr = havingClause;

                // TODO: this requires a visitor to modify the having expression
                havingExpr = ReplaceAliasedVariables(havingExpr, selectColumns);

                var source = tablePlanner.SinglePlan;
                source.UpdatePlan(node);
                node = tablePlanner.PlanSearchExpression(havingExpr);
            }

            // Do we have a composite select expression to process?
            IQueryPlanNode rightComposite = null;

            if (queryExpression.NextComposite != null)
            {
                var compositeExpr = queryExpression.NextComposite;
                var compositeFrom = QueryExpressionFrom.Create(context, compositeExpr);

                // Form the right plan
                rightComposite = PlanQuery(context, compositeExpr, compositeFrom, null, null);
            }

            // Do we do a final subset column?
            ObjectName[] aliases = null;
            if (doSubsetColumn)
            {
                // Make up the lists
                var subsetVars = new ObjectName[sz];
                aliases = new ObjectName[sz];
                for (int i = 0; i < sz; ++i)
                {
                    SelectColumn scol = selectColumns[i];
                    subsetVars[i] = scol.InternalName;
                    aliases[i]    = scol.ResolvedName;
                }

                // If we are distinct then add the DistinctNode here
                if (queryExpression.Distinct)
                {
                    node = new DistinctNode(node, subsetVars);
                }

                // Process the ORDER BY?
                // Note that the ORDER BY has to occur before the subset call, but
                // after the distinct because distinct can affect the ordering of the
                // result.
                if (rightComposite == null && sortColumns != null)
                {
                    node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);
                }

                // Rename the columns as specified in the SELECT
                node = new SubsetNode(node, subsetVars, aliases);
            }
            else
            {
                // Process the ORDER BY?
                if (rightComposite == null && sortColumns != null)
                {
                    node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);
                }
            }

            // Do we have a composite to merge in?
            if (rightComposite != null)
            {
                // For the composite
                node = new CompositeNode(node, rightComposite, queryExpression.CompositeFunction, queryExpression.IsCompositeAll);

                // Final order by?
                if (sortColumns != null)
                {
                    node = PlanForOrderBy(node, sortColumns, queryFrom, selectColumns);
                }

                // Ensure a final subset node
                if (!(node is SubsetNode) && aliases != null)
                {
                    node = new SubsetNode(node, aliases, aliases);
                }
            }

            if (limit != null)
            {
                node = new LimitNode(node, limit.Offset, limit.Count);
            }

            return(node);
        }