Beispiel #1
0
        public override QueryNode VisitSelectQuery(SelectQuery query)
        {
            PushQueryScope(query.QueryScope);

            // Validate all embedded AST entries that need to check a query context.

            _queryNestingLevel++;
            QueryNode result = base.VisitSelectQuery(query);

            _queryNestingLevel--;

            // Validate DISTINCT

            if (query.IsDistinct)
            {
                // Ensure that all column sources are datatypes that are comparable.

                foreach (SelectColumn columnSource in query.SelectColumns)
                {
                    if (!CheckIfTypeIsComparable(columnSource.Expression.ExpressionType))
                    {
                        _errorReporter.InvalidDataTypeInSelectDistinct(columnSource.Expression.ExpressionType);
                    }
                }
            }

            // Validate TOP

            if (query.TopClause != null)
            {
                if (query.TopClause.WithTies && query.OrderByColumns == null)
                {
                    _errorReporter.TopWithTiesRequiresOrderBy();
                }
            }

            // Ensure that all ORDER BY datatypes are comparable.

            if (query.OrderByColumns != null)
            {
                ValidateOrderByClause(query.OrderByColumns);
            }

            // Ensure that if both DISTINCT and ORDER BY are presents all expressions in ORDER BY are also part in SELECT.

            if (query.IsDistinct && query.OrderByColumns != null)
            {
                bool allColumnsAreInInput = GetAllColumnsAreInInput(query.SelectColumns, query.OrderByColumns);
                if (!allColumnsAreInInput)
                {
                    _errorReporter.OrderByItemsMustBeInSelectListIfDistinctSpecified();
                }
            }

            // Validate GROUP BY and aggregation-only queries.

            if (query.GroupByColumns == null)
            {
                if (query.IsAggregated || query.HavingClause != null)
                {
                    // No grouping applied but at least one aggregation function present. That
                    // means we have an aggregation-only query.
                    //
                    // Check that all expressions in SELECT are either aggregated or do not
                    // reference any column.

                    foreach (SelectColumn columnSource in query.SelectColumns)
                    {
                        foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(null, columnSource.Expression))
                        {
                            if (referencedColumn.Scope == query.QueryScope)
                            {
                                // The column is not an outer reference so this is an error.
                                _errorReporter.SelectExpressionNotAggregatedAndNoGroupBy(referencedColumn);
                            }
                        }
                    }

                    // Check that all expressions in HAVING are either aggregated or do not
                    // reference any column.

                    if (query.HavingClause != null)
                    {
                        foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(null, query.HavingClause))
                        {
                            if (referencedColumn.Scope == query.QueryScope)
                            {
                                // The column is not an outer reference so this is an error.
                                _errorReporter.HavingExpressionNotAggregatedOrGrouped(referencedColumn);
                            }
                        }
                    }

                    // Check that all expressions in ORDER BY are either aggregated or do not
                    // reference any column.

                    if (query.OrderByColumns != null)
                    {
                        foreach (OrderByColumn orderByColumn in query.OrderByColumns)
                        {
                            foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(null, orderByColumn.Expression))
                            {
                                if (referencedColumn.Scope == query.QueryScope)
                                {
                                    // The column is not an outer reference so this is an error.
                                    _errorReporter.OrderByExpressionNotAggregatedAndNoGroupBy(referencedColumn);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                // Grouped query:
                //
                // 1. All expression in GROUP BY must have a datatype that is comparable.
                //
                // 2. All expressions in GROUP BY must not be aggregated
                //
                // 3. All expressions in SELECT, ORDER BY, and HAVING must be aggregated, grouped or must not reference
                //    columns.

                // Check that all GROUP BY expressions are not aggregated.

                foreach (ExpressionNode groupExpression in query.GroupByColumns)
                {
                    if (!CheckIfTypeIsComparable(groupExpression.ExpressionType))
                    {
                        _errorReporter.InvalidDataTypeInGroupBy(groupExpression.ExpressionType);
                    }

                    MetaInfo metaInfo = AstUtil.GetMetaInfo(groupExpression);
                    if (metaInfo.ColumnDependencies.Length == 0)
                    {
                        _errorReporter.GroupByItemDoesNotReferenceAnyColumns();
                    }
                }

                // Check that all expressions in SELECT are either part of the GROUP BY or are referencing only those
                // columns that are part of the GROUP BY.

                foreach (SelectColumn columnSource in query.SelectColumns)
                {
                    foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(query.GroupByColumns, columnSource.Expression))
                    {
                        if (referencedColumn.Scope == query.QueryScope)
                        {
                            // The column is not an outer reference so this is an error.
                            _errorReporter.SelectExpressionNotAggregatedOrGrouped(referencedColumn);
                        }
                    }
                }

                // Check that all expressions in HAVING are either part of the GROUP BY or are referencing only those
                // columns that are part of the GROUP BY.

                if (query.HavingClause != null)
                {
                    foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(query.GroupByColumns, query.HavingClause))
                    {
                        if (referencedColumn.Scope == query.QueryScope)
                        {
                            // The column is not an outer reference so this is an error.
                            _errorReporter.HavingExpressionNotAggregatedOrGrouped(referencedColumn);
                        }
                    }
                }

                // Check that all expressions in the ORDER BY clause are either part of the GROUP BY or are
                // referencing only those columns that are part of the GROUP BY.

                if (query.OrderByColumns != null)
                {
                    foreach (OrderByColumn orderByColumn in query.OrderByColumns)
                    {
                        foreach (ColumnRefBinding referencedColumn in AstUtil.GetUngroupedAndUnaggregatedColumns(query.GroupByColumns, orderByColumn.Expression))
                        {
                            if (referencedColumn.Scope == query.QueryScope)
                            {
                                // The column is not an outer reference so this is an error.
                                _errorReporter.OrderByExpressionNotAggregatedOrGrouped(referencedColumn);
                            }
                        }
                    }
                }
            }

            PopQueryScope();
            return(result);
        }