SemanticResolver.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Common / EntitySql / SemanticResolver.cs / 1305376 / SemanticResolver.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 

namespace System.Data.Common.EntitySql 
{
    using System;
    using System.IO;
    using System.Globalization; 
    using System.Collections.Generic;
    using System.Diagnostics; 
    using System.Linq; 

    using System.Data.Mapping; 
    using System.Data.Common.CommandTrees;
    using System.Data.Common;
    using System.Data.Metadata.Edm;
    using System.Data.Entity; 
    using System.Data.Common.CommandTrees.ExpressionBuilder;
 
    ///  
    /// Represents eSQL expression class.
    ///  
    internal enum ExpressionResolutionClass
    {
        /// 
        /// A value expression such as a literal, variable or a value-returning expression. 
        /// 
        Value, 
        ///  
        /// An expression returning an entity container.
        ///  
        EntityContainer,
        /// 
        /// An expression returning a metadata member such as a type, function group or namespace.
        ///  
        MetadataMember
    } 
 
    /// 
    /// Abstract class representing the result of an eSQL expression classification. 
    /// 
    internal abstract class ExpressionResolution
    {
        protected ExpressionResolution(ExpressionResolutionClass @class) 
        {
            ExpressionClass = @class; 
        } 

        internal readonly ExpressionResolutionClass ExpressionClass; 
        internal abstract string ExpressionClassName { get; }
    }

    ///  
    /// Represents an eSQL expression classified as .
    ///  
    internal sealed class ValueExpression : ExpressionResolution 
    {
        internal ValueExpression(DbExpression value) 
            : base(ExpressionResolutionClass.Value)
        {
            Value = value;
        } 

        internal override string ExpressionClassName { get { return ValueClassName; } } 
        internal static string ValueClassName { get { return Strings.LocalizedValueExpression; } } 

        internal readonly DbExpression Value; 
    }

    /// 
    /// Represents an eSQL expression classified as . 
    /// 
    internal sealed class EntityContainerExpression : ExpressionResolution 
    { 
        internal EntityContainerExpression(EntityContainer entityContainer)
            : base(ExpressionResolutionClass.EntityContainer) 
        {
            EntityContainer = entityContainer;
        }
 
        internal override string ExpressionClassName { get { return EntityContainerClassName; } }
        internal static string EntityContainerClassName { get { return Strings.LocalizedEntityContainerExpression; } } 
 
        internal readonly EntityContainer EntityContainer;
    } 

    /// 
    /// Implements the semantic resolver in the context of a metadata workspace and typespace.
    ///  
    /// not thread safe
    internal sealed class SemanticResolver 
    { 
        #region Fields
        ///  
        /// eSQL parser is case-insensitive.
        /// 
        private static readonly StringComparer _stringComparer = StringComparer.OrdinalIgnoreCase;
        private readonly ParserOptions _parserOptions; 
        private readonly Dictionary _parameters;
        private readonly Dictionary _variables; 
        private readonly TypeResolver _typeResolver; 
        private readonly ScopeManager _scopeManager;
        private readonly List _scopeRegions = new List(); 
        private bool _ignoreEntityContainerNameResolution = false;
        private GroupAggregateInfo _currentGroupAggregateInfo = null;
        private uint _namegenCounter = 0;
        #endregion 

        #region Constructors 
        ///  
        /// Creates new instance of .
        ///  
        internal static SemanticResolver Create(Perspective perspective,
                                                ParserOptions parserOptions,
                                                IEnumerable parameters,
                                                IEnumerable variables) 
        {
            EntityUtil.CheckArgumentNull(perspective, "perspective"); 
            EntityUtil.CheckArgumentNull(parserOptions, "parserOptions"); 

            return new SemanticResolver( 
                parserOptions,
                ProcessParameters(parameters),
                ProcessVariables(variables),
                new TypeResolver(perspective, _stringComparer)); 
        }
 
        ///  
        /// Creates a copy of  with clean scopes and shared inline function definitions inside of the type resolver.
        ///  
        internal SemanticResolver CloneForInlineFunctionConversion()
        {
            return new SemanticResolver(
                 _parserOptions, 
                 _parameters,
                 _variables, 
                 _typeResolver); 
        }
 
        private SemanticResolver(ParserOptions parserOptions,
                                 Dictionary parameters,
                                 Dictionary variables,
                                 TypeResolver typeResolver) 
        {
            _parserOptions = parserOptions; 
            _parameters = parameters; 
            _variables = variables;
            _typeResolver = typeResolver; 

            //
            // Creates Scope manager
            // 
            _scopeManager = new ScopeManager(_stringComparer);
 
            // 
            // Push a root scope region
            // 
            EnterScopeRegion();

            //
            // Add command free variables to the root scope 
            //
            foreach (DbVariableReferenceExpression variable in _variables.Values) 
            { 
                this.CurrentScope.Add(variable.VariableName, new FreeVariableScopeEntry(variable));
            } 
        }

        /// 
        /// Validates that the specified parameters have valid, non-duplicated names 
        /// 
        /// The set of query parameters 
        /// A valid dictionary that maps parameter names to s using the current StringComparer 
        private static Dictionary ProcessParameters(IEnumerable paramDefs)
        { 
            Dictionary retParams = new Dictionary(_stringComparer);

            if (paramDefs != null)
            { 
                foreach (DbParameterReferenceExpression paramDef in paramDefs)
                { 
                    if (retParams.ContainsKey(paramDef.ParameterName)) 
                    {
                        throw EntityUtil.EntitySqlError(Strings.MultipleDefinitionsOfParameter(paramDef.ParameterName)); 
                    }

                    Debug.Assert(paramDef.ResultType.IsReadOnly, "paramDef.ResultType.IsReadOnly must be set");
 
                    retParams.Add(paramDef.ParameterName, paramDef);
                } 
            } 

            return retParams; 
        }

        /// 
        /// Validates that the specified variables have valid, non-duplicated names 
        /// 
        /// The set of free variables 
        /// A valid dictionary that maps variable names to s using the current StringComparer 
        private static Dictionary ProcessVariables(IEnumerable varDefs)
        { 
            Dictionary retVars = new Dictionary(_stringComparer);

            if (varDefs != null)
            { 
                foreach (DbVariableReferenceExpression varDef in varDefs)
                { 
                    if (retVars.ContainsKey(varDef.VariableName)) 
                    {
                        throw EntityUtil.EntitySqlError(Strings.MultipleDefinitionsOfVariable(varDef.VariableName)); 
                    }

                    Debug.Assert(varDef.ResultType.IsReadOnly, "varDef.ResultType.IsReadOnly must be set");
 
                    retVars.Add(varDef.VariableName, varDef);
                } 
            } 

            return retVars; 
        }
        #endregion

        #region Properties 
        /// 
        /// Returns ordinary command parameters. Empty dictionary in case of no parameters. 
        ///  
        internal Dictionary Parameters
        { 
            get { return _parameters; }
        }

        ///  
        /// Returns command free variables. Empty dictionary in case of no variables.
        ///  
        internal Dictionary Variables 
        {
            get { return _variables; } 
        }

        /// 
        /// TypeSpace/Metadata/Perspective dependent type resolver. 
        /// 
        internal TypeResolver TypeResolver 
        { 
            get { return _typeResolver; }
        } 

        /// 
        /// Returns current Parser Options.
        ///  
        internal ParserOptions ParserOptions
        { 
            get { return _parserOptions; } 
        }
 
        /// 
        /// Returns the current string comparer.
        /// 
        internal StringComparer StringComparer 
        {
            get { return _stringComparer; } 
        } 

        ///  
        /// Returns the list of scope regions: outer followed by inner.
        /// 
        internal IEnumerable ScopeRegions
        { 
            get { return _scopeRegions; }
        } 
 
        /// 
        /// Returns the current scope region. 
        /// 
        internal ScopeRegion CurrentScopeRegion
        {
            get { return _scopeRegions[_scopeRegions.Count - 1]; } 
        }
 
        ///  
        /// Returns the current scope.
        ///  
        internal Scope CurrentScope
        {
            get { return _scopeManager.CurrentScope; }
        } 

        ///  
        /// Returns index of the current scope. 
        /// 
        internal int CurrentScopeIndex 
        {
            get { return _scopeManager.CurrentScopeIndex; }
        }
 
        /// 
        /// Returns the current group aggregate info when processing group aggregate argument. 
        ///  
        internal GroupAggregateInfo CurrentGroupAggregateInfo
        { 
            get { return _currentGroupAggregateInfo; }
        }
        #endregion
 
        #region GetExpressionFromScopeEntry
        ///  
        /// Returns the appropriate expression from a given scope entry. 
        /// May return null for scope entries like .
        ///  
        private DbExpression GetExpressionFromScopeEntry(ScopeEntry scopeEntry, int scopeIndex, string varName, ErrorContext errCtx)
        {
            //
            // If 
            //      1) we are in the context of a group aggregate or group key,
            //      2) and the scopeEntry can have multiple interpretations depending on the aggregation context, 
            //      3) and the defining scope region of the scopeEntry is outer or equal to the defining scope region of the group aggregate, 
            //      4) and the defining scope region of the scopeEntry is not performing conversion of a group key definition,
            // Then the expression that corresponds to the scopeEntry is either the GroupVarBasedExpression or the GroupAggBasedExpression. 
            // Otherwise the default expression that corresponds to the scopeEntry is provided by scopeEntry.GetExpression(...) call.
            //
            // Explanation for #2 from the list above:
            // A scope entry may have multiple aggregation-context interpretations: 
            //      - An expression in the context of a group key definition, obtained by scopeEntry.GetExpression(...);
            //        Example: select k1 from {0} as a group by a%2 as k1 
            //                                                  ^^^ 
            //      - An expression in the context of a function aggregate, provided by iGroupExpressionExtendedInfo.GroupVarBasedExpression;
            //        Example: select max( a ) from {0} as a group by a%2 as k1 
            //                            ^^^
            //      - An expression in the context of a group partition, provided by iGroupExpressionExtendedInfo.GroupAggBasedExpression;
            //        Example: select GroupPartition( a ) from {0} as a group by a%2 as k1
            //                                       ^^^ 
            // Note that expressions obtained from aggregation-context-dependent scope entries outside of the three contexts mentioned above
            // will default to the value returned by the scopeEntry.GetExpression(...) call. This value is the same as in the group key definition context. 
            // These expressions have correct result types which enables partial expression validation. 
            // However the contents of the expressions are invalid outside of the group key definitions, hence they can not appear in the final expression tree.
            // SemanticAnalyzer.ProcessGroupByClause(...) method guarantees that such expressions are only temporarily used during GROUP BY clause processing and 
            // dropped afterwards.
            // Example: select a, k1 from {0} as a group by a%2 as k1
            //                 ^^^^^ - these expressions are processed twice: once during GROUP BY and then SELECT clause processing,
            //                         the expressions obtained during GROUP BY clause processing are dropped and only 
            //                         the ones obtained during SELECT clause processing are accepted.
            // 
            // Explanation for #3 from the list above: 
            //      - An outer scope entry referenced inside of an aggregate may lift the aggregate to the outer scope region for evaluation,
            //        hence such a scope entry must be interpreted in the aggregation context. See explanation for #4 below for more info. 
            //        Example:
            //
            //          select
            //              (select max(x) from {1} as y) 
            //          from {0} as x
            // 
            //      - If a scope entry is defined inside of a group aggregate, then the scope entry is not affected by the aggregate, 
            //        hence such a scope entry is not interpreted in the aggregation context.
            //        Example: 
            //
            //          select max(
            //                       anyelement( select b from {1} as b )
            //                    ) 
            //          from {0} as a group by a %2 as a1
            // 
            //        In this query the aggregate argument contains a nested query expression. 
            //        The nested query references b. Because b is defined inside of the aggregate it is not interpreted in the aggregation context and
            //        the expression for b should not be GroupVar/GroupAgg based, even though the reference to b appears inside of an aggregate. 
            //
            // Explanation for #4 from the list above:
            // An aggregate evaluating on a particular scope region defines the interpretation of scope entries defined on that scope region.
            // In the case when an inner aggregate references a scope entry belonging to the evaluating region of an outer aggregate, the interpretation 
            // of the scope entry is controlled by the outer aggregate, otherwise it is controlled by the inner aggregate.
            // Example: 
            // 
            //      select a1
            //      from {0} as a group by 
            //                                anyelement(select value max(a + b) from {1} as b)
            //                          as a1
            //
            // In this query the aggregate inside of a1 group key definition, the max(a + b), references scope entry a. 
            // Because a is referenced inside of the group key definition (which serves as an outer aggregate) and the key definition belongs to
            // the same scope region as a, a is interpreted in the context of the group key definition, not the function aggregate and 
            // the expression for a is obtained by scopeEntry.GetExpression(...) call, not iGroupExpressionExtendedInfo.GroupVarBasedExpression. 
            //
 
            DbExpression expr = scopeEntry.GetExpression(varName, errCtx);
            Debug.Assert(expr != null, "scopeEntry.GetExpression(...) returned null");

            if (_currentGroupAggregateInfo != null) 
            {
                // 
                // Make sure defining scope regions agree as described above. 
                // Outer scope region has smaller index value than the inner.
                // 
                ScopeRegion definingScopeRegionOfScopeEntry = GetDefiningScopeRegion(scopeIndex);
                if (definingScopeRegionOfScopeEntry.ScopeRegionIndex <= _currentGroupAggregateInfo.DefiningScopeRegion.ScopeRegionIndex)
                {
                    // 
                    // Let the group aggregate know the scope of the scope entry it references.
                    // This affects the scope region that will evaluate the group aggregate. 
                    // 
                    _currentGroupAggregateInfo.UpdateScopeIndex(scopeIndex, this);
 
                    IGroupExpressionExtendedInfo iGroupExpressionExtendedInfo = scopeEntry as IGroupExpressionExtendedInfo;
                    if (iGroupExpressionExtendedInfo != null)
                    {
                        // 
                        // Find the aggregate that controls interpretation of the current scope entry.
                        // This would be a containing aggregate with the defining scope region matching definingScopeRegionOfScopeEntry. 
                        // If there is no such aggregate, then the current containing aggregate controls interpretation. 
                        //
                        GroupAggregateInfo expressionInterpretationContext; 
                        for (expressionInterpretationContext = _currentGroupAggregateInfo;
                             expressionInterpretationContext != null &&
                             expressionInterpretationContext.DefiningScopeRegion.ScopeRegionIndex >= definingScopeRegionOfScopeEntry.ScopeRegionIndex;
                             expressionInterpretationContext = expressionInterpretationContext.ContainingAggregate) 
                        {
                            if (expressionInterpretationContext.DefiningScopeRegion.ScopeRegionIndex == definingScopeRegionOfScopeEntry.ScopeRegionIndex) 
                            { 
                                break;
                            } 
                        }
                        if (expressionInterpretationContext == null ||
                            expressionInterpretationContext.DefiningScopeRegion.ScopeRegionIndex < definingScopeRegionOfScopeEntry.ScopeRegionIndex)
                        { 
                            expressionInterpretationContext = _currentGroupAggregateInfo;
                        } 
 
                        switch (expressionInterpretationContext.AggregateKind)
                        { 
                            case GroupAggregateKind.Function:
                                if (iGroupExpressionExtendedInfo.GroupVarBasedExpression != null)
                                {
                                    expr = iGroupExpressionExtendedInfo.GroupVarBasedExpression; 
                                }
                                break; 
 
                            case GroupAggregateKind.Partition:
                                if (iGroupExpressionExtendedInfo.GroupAggBasedExpression != null) 
                                {
                                    expr = iGroupExpressionExtendedInfo.GroupAggBasedExpression;
                                }
                                break; 

                            case GroupAggregateKind.GroupKey: 
                                // 
                                // User the current expression obtained from scopeEntry.GetExpression(...)
                                // 
                                break;

                            default:
                                Debug.Fail("Unexpected group aggregate kind."); 
                                break;
                        } 
                    } 
                }
            } 

            return expr;
        }
        #endregion 

        #region Name resolution 
        #region Resolve simple / metadata member name 
        internal IDisposable EnterIgnoreEntityContainerNameResolution()
        { 
            Debug.Assert(!_ignoreEntityContainerNameResolution, "EnterIgnoreEntityContainerNameResolution() is not reentrant.");
            _ignoreEntityContainerNameResolution = true;
            return new Disposer(delegate
            { 
                Debug.Assert(this._ignoreEntityContainerNameResolution, "_ignoreEntityContainerNameResolution must be true.");
                this._ignoreEntityContainerNameResolution = false; 
            }); 
        }
 
        internal ExpressionResolution ResolveSimpleName(string name, bool leftHandSideOfMemberAccess, ErrorContext errCtx)
        {
            Debug.Assert(!String.IsNullOrEmpty(name), "name must not be null or empty");
 
            //
            // Try resolving as a scope entry. 
            // 
            ScopeEntry scopeEntry;
            int scopeIndex; 
            if (TryScopeLookup(name, out scopeEntry, out scopeIndex))
            {
                //
                // Check for invalid join left expression correlation. 
                //
                if (scopeEntry.EntryKind == ScopeEntryKind.SourceVar && ((SourceScopeEntry)scopeEntry).IsJoinClauseLeftExpr) 
                { 
                    throw EntityUtil.EntitySqlError(errCtx, Strings.InvalidJoinLeftCorrelation);
                } 

                //
                // Set correlation flag.
                // 
                SetScopeRegionCorrelationFlag(scopeIndex);
 
                return new ValueExpression(GetExpressionFromScopeEntry(scopeEntry, scopeIndex, name, errCtx)); 
            }
 
            //
            // Try resolving as an entity set inside of the default entity container.
            //
            EntityContainer entityContainer = this.TypeResolver.Perspective.GetDefaultContainer(); 
            EntitySetBase entitySetBase;
            if (entityContainer != null && this.TypeResolver.Perspective.TryGetExtent(entityContainer, name, true /*ignoreCase*/, out entitySetBase)) 
            { 
                return new ValueExpression(entitySetBase.Scan());
            } 

            if (!_ignoreEntityContainerNameResolution)
            {
                // 
                // Try resolving as an entity container.
                // 
                if (this.TypeResolver.Perspective.TryGetEntityContainer(name, true /*ignoreCase*/, out entityContainer)) 
                {
                    return new EntityContainerExpression(entityContainer); 
                }
            }

            // 
            // Otherwise, resolve as an unqualified name.
            // 
            return this.TypeResolver.ResolveUnqualifiedName(name, leftHandSideOfMemberAccess /* partOfQualifiedName */, errCtx); 
        }
 
        /// 
        /// Performs scope lookup returning the scope entry and its index.
        /// 
        private bool TryScopeLookup(string key, out ScopeEntry scopeEntry, out int scopeIndex) 
        {
            scopeEntry = null; 
            scopeIndex = -1; 

            for (int i = CurrentScopeIndex; i >= 0; i--) 
            {
                if (_scopeManager.GetScopeByIndex(i).TryLookup(key, out scopeEntry))
                {
                    scopeIndex = i; 
                    return true;
                } 
            } 

            return false; 
        }

        internal MetadataMember ResolveMetadataMemberName(string[] name, ErrorContext errCtx)
        { 
            return this.TypeResolver.ResolveMetadataMemberName(name, errCtx);
        } 
        #endregion 

        #region Resolve member name in member access 
        #region Resolve property access
        /// 
        /// Resolve property  off the .
        ///  
        internal ValueExpression ResolvePropertyAccess(DbExpression valueExpr, string name, ErrorContext errCtx)
        { 
            DbExpression propertyExpr; 

            if (TryResolveAsPropertyAccess(valueExpr, name, errCtx, out propertyExpr)) 
            {
                return new ValueExpression(propertyExpr);
            }
 
            if (TryResolveAsRefPropertyAccess(valueExpr, name, errCtx, out propertyExpr))
            { 
                return new ValueExpression(propertyExpr); 
            }
 
            if (TypeSemantics.IsCollectionType(valueExpr.ResultType))
            {
                throw EntityUtil.EntitySqlError(errCtx, Strings.NotAMemberOfCollection(name, valueExpr.ResultType.EdmType.FullName));
            } 
            else
            { 
                throw EntityUtil.EntitySqlError(errCtx, Strings.NotAMemberOfType(name, valueExpr.ResultType.EdmType.FullName)); 
            }
        } 

        /// 
        /// Try resolving  as a property of the value returned by the .
        ///  
        private bool TryResolveAsPropertyAccess(DbExpression valueExpr, string name, ErrorContext errCtx, out DbExpression propertyExpr)
        { 
            Debug.Assert(valueExpr != null, "valueExpr != null"); 

            propertyExpr = null; 

            if (Helper.IsStructuralType(valueExpr.ResultType.EdmType))
            {
                EdmMember member = null; 
                if (TypeResolver.Perspective.TryGetMember((StructuralType)valueExpr.ResultType.EdmType, name, true, out member))
                { 
                    if (null != member) 
                    {
                        Debug.Assert(_stringComparer.Equals(name, member.Name), "_stringComparer.Equals(name, member.Name)"); 
                        propertyExpr = valueExpr.PropertyIgnoreCase(name);
                        return true;
                    }
                } 
            }
 
            return false; 
        }
 
        /// 
        /// If  returns a reference, then deref and try resolving  as a property of the dereferenced value.
        /// 
        private bool TryResolveAsRefPropertyAccess(DbExpression valueExpr, string name, ErrorContext errCtx, out DbExpression propertyExpr) 
        {
            Debug.Assert(valueExpr != null, "valueExpr != null"); 
 
            propertyExpr = null;
 
            if (TypeSemantics.IsReferenceType(valueExpr.ResultType))
            {
                DbExpression derefExpr = valueExpr.Deref();
                TypeUsage derefExprType = derefExpr.ResultType; 

                if (TryResolveAsPropertyAccess(derefExpr, name, errCtx, out propertyExpr)) 
                { 
                    return true;
                } 
                else
                {
                    throw EntityUtil.EntitySqlError(errCtx, Strings.InvalidDeRefProperty(name, TypeHelpers.GetFullName(derefExprType), TypeHelpers.GetFullName(valueExpr.ResultType)));
                } 
            }
 
            return false; 
        }
        #endregion 

        #region Resolve entity set access
        /// 
        /// Resolve entity set  in the  
        /// 
        internal ValueExpression ResolveEntitySetAccess(EntityContainer entityContainer, string name, ErrorContext errCtx) 
        { 
            EntitySetBase entitySetBase;
            if (this.TypeResolver.Perspective.TryGetExtent(entityContainer, name, true /*ignoreCase*/, out entitySetBase)) 
            {
                return new ValueExpression(entitySetBase.Scan());
            }
            else 
            {
                throw EntityUtil.EntitySqlError(errCtx, Strings.EntitySetDoesNotBelongToEntityContainer(name, entityContainer.Name)); 
            } 
        }
        #endregion 

        #region Resolve metadata member access
        /// 
        /// Resolve namespace, type or function  in the  
        /// 
        internal MetadataMember ResolveMetadataMemberAccess(MetadataMember metadataMember, string name, ErrorContext errCtx) 
        { 
            return this.TypeResolver.ResolveMetadataMemberAccess(metadataMember, name, errCtx);
        } 
        #endregion
        #endregion

        #region Resolve internal aggregate name / alternative group key name 
        /// 
        /// Try resolving an internal aggregate name. 
        ///  
        internal bool TryResolveInternalAggregateName(string name, ErrorContext errCtx, out DbExpression dbExpression)
        { 
            ScopeEntry scopeEntry;
            int scopeIndex;
            if (TryScopeLookup(name, out scopeEntry, out scopeIndex))
            { 
                //
                // Set the correlation flag. 
                // 
                SetScopeRegionCorrelationFlag(scopeIndex);
 
                dbExpression = scopeEntry.GetExpression(name, errCtx);
                return true;
            }
            else 
            {
                dbExpression = null; 
                return false; 
            }
        } 
        /// 
        /// Try resolving multipart identifier as an alternative name of a group key (see SemanticAnalyzer.ProcessGroupByClause(...) for more info).
        /// 
        internal bool TryResolveDotExprAsGroupKeyAlternativeName(AST.DotExpr dotExpr, out ValueExpression groupKeyResolution) 
        {
            groupKeyResolution = null; 
 
            string[] names;
            ScopeEntry scopeEntry; 
            int scopeIndex;
            if (IsInAnyGroupScope() &&
                dotExpr.IsMultipartIdentifier(out names) &&
                TryScopeLookup(TypeResolver.GetFullName(names), out scopeEntry, out scopeIndex)) 
            {
                IGetAlternativeName iGetAlternativeName = scopeEntry as IGetAlternativeName; 
 
                //
                // Accept only if names[] match alternative name part by part. 
                //
                if (iGetAlternativeName != null && iGetAlternativeName.AlternativeName != null &&
                    names.SequenceEqual(iGetAlternativeName.AlternativeName, _stringComparer))
                { 
                    //
                    // Set correlation flag 
                    // 
                    SetScopeRegionCorrelationFlag(scopeIndex);
 
                    groupKeyResolution = new ValueExpression(GetExpressionFromScopeEntry(scopeEntry, scopeIndex, TypeResolver.GetFullName(names), dotExpr.ErrCtx));
                    return true;
                }
            } 
            return false;
        } 
        #endregion 
        #endregion
 
        #region Name generation utils (GenerateInternalName, CreateNewAlias, InferAliasName)
        /// 
        /// Generates unique internal name.
        ///  
        internal string GenerateInternalName(string hint)
        { 
            // string concat is much faster than String.Format 
            return "_##" + hint + unchecked(_namegenCounter++).ToString(CultureInfo.InvariantCulture);
        } 

        /// 
        /// Creates a new alias name based on the  information.
        ///  
        private string CreateNewAlias(DbExpression expr)
        { 
            DbScanExpression extent = expr as DbScanExpression; 
            if (null != extent)
            { 
                return extent.Target.Name;
            }

            DbPropertyExpression property = expr as DbPropertyExpression; 
            if (null != property)
            { 
                return property.Property.Name; 
            }
 
            DbVariableReferenceExpression varRef = expr as DbVariableReferenceExpression;
            if (null != varRef)
            {
                return varRef.VariableName; 
            }
 
            return GenerateInternalName(String.Empty); 
        }
 
        /// 
        /// Returns alias name from  ast node if it contains an alias,
        /// otherwise creates a new alias name based on the .Expr or  information.
        ///  
        internal string InferAliasName(AST.AliasedExpr aliasedExpr, DbExpression convertedExpression)
        { 
            if (aliasedExpr.Alias != null) 
            {
                return aliasedExpr.Alias.Name; 
            }

            AST.Identifier id = aliasedExpr.Expr as AST.Identifier;
            if (null != id) 
            {
                return id.Name; 
            } 

            AST.DotExpr dotExpr = aliasedExpr.Expr as AST.DotExpr; 
            string[] names;
            if (null != dotExpr && dotExpr.IsMultipartIdentifier(out names))
            {
                return names[names.Length - 1]; 
            }
 
            return CreateNewAlias(convertedExpression); 
        }
        #endregion 

        #region Scope/ScopeRegion utils
        /// 
        /// Enters a new scope region. 
        /// 
        internal IDisposable EnterScopeRegion() 
        { 
            //
            // Push new scope (the first scope in the new scope region) 
            //
            _scopeManager.EnterScope();

            // 
            // Create new scope region and push it
            // 
            ScopeRegion scopeRegion = new ScopeRegion(_scopeManager, CurrentScopeIndex, _scopeRegions.Count); 
            _scopeRegions.Add(scopeRegion);
 
            //
            // Return scope region disposer that rolls back the scope.
            //
            return new Disposer(delegate 
                {
                    Debug.Assert(this.CurrentScopeRegion == scopeRegion, "Scope region stack is corrupted."); 
 
                    //
                    // Root scope region is permanent. 
                    //
                    Debug.Assert(this._scopeRegions.Count > 1, "_scopeRegionFlags.Count > 1");

                    // 
                    // Reset aggregate info of AST nodes of aggregates resolved to the CurrentScopeRegion.
                    // 
                    this.CurrentScopeRegion.GroupAggregateInfos.ForEach(groupAggregateInfo => groupAggregateInfo.DetachFromAstNode()); 

                    // 
                    // Rollback scopes of the region.
                    //
                    this.CurrentScopeRegion.RollbackAllScopes();
 
                    //
                    // Remove the scope region. 
                    // 
                    this._scopeRegions.Remove(CurrentScopeRegion);
                }); 
        }

        /// 
        /// Rollback all scopes above the . 
        /// 
        internal void RollbackToScope(int scopeIndex) 
        { 
            _scopeManager.RollbackToScope(scopeIndex);
        } 

        /// 
        /// Enter a new scope.
        ///  
        internal void EnterScope()
        { 
            _scopeManager.EnterScope(); 
        }
 
        /// 
        /// Leave the current scope.
        /// 
        internal void LeaveScope() 
        {
            _scopeManager.LeaveScope(); 
        } 

        ///  
        /// Returns true if any of the ScopeRegions from the closest to the outermost has IsAggregating = true
        /// 
        internal bool IsInAnyGroupScope()
        { 
            for (int i = 0; i < _scopeRegions.Count; i++)
            { 
                if (_scopeRegions[i].IsAggregating) 
                {
                    return true; 
                }
            }
            return false;
        } 

        internal ScopeRegion GetDefiningScopeRegion(int scopeIndex) 
        { 
            //
            // Starting from the innermost, find the outermost scope region that contains the scope. 
            //
            for (int i = _scopeRegions.Count - 1; i >= 0; --i)
            {
                if (_scopeRegions[i].ContainsScope(scopeIndex)) 
                {
                    return _scopeRegions[i]; 
                } 
            }
            Debug.Fail("Failed to find the defining scope region for the given scope."); 
            return null;
        }

        ///  
        /// Sets the scope region correlation flag based on the scope index of the referenced scope entry.
        ///  
        private void SetScopeRegionCorrelationFlag(int scopeIndex) 
        {
            GetDefiningScopeRegion(scopeIndex).WasResolutionCorrelated = true; 
        }
        #endregion

        #region Group aggregate utils 
        /// 
        /// Enters processing of a function group aggregate. 
        ///  
        internal IDisposable EnterFunctionAggregate(AST.MethodExpr methodExpr, ErrorContext errCtx, out FunctionAggregateInfo aggregateInfo)
        { 
            aggregateInfo = new FunctionAggregateInfo(methodExpr, errCtx, _currentGroupAggregateInfo, CurrentScopeRegion);
            return EnterGroupAggregate(aggregateInfo);
        }
 
        /// 
        /// Enters processing of a group partition aggregate. 
        ///  
        internal IDisposable EnterGroupPartition(AST.GroupPartitionExpr groupPartitionExpr, ErrorContext errCtx, out GroupPartitionInfo aggregateInfo)
        { 
            aggregateInfo = new GroupPartitionInfo(groupPartitionExpr, errCtx, _currentGroupAggregateInfo, CurrentScopeRegion);
            return EnterGroupAggregate(aggregateInfo);
        }
 
        /// 
        /// Enters processing of a group partition aggregate. 
        ///  
        internal IDisposable EnterGroupKeyDefinition(GroupAggregateKind aggregateKind, ErrorContext errCtx, out GroupKeyAggregateInfo aggregateInfo)
        { 
            aggregateInfo = new GroupKeyAggregateInfo(aggregateKind, errCtx, _currentGroupAggregateInfo, CurrentScopeRegion);
            return EnterGroupAggregate(aggregateInfo);
        }
 
        private IDisposable EnterGroupAggregate(GroupAggregateInfo aggregateInfo)
        { 
            _currentGroupAggregateInfo = aggregateInfo; 
            return new Disposer(delegate
                { 
                    //
                    // First, pop the element from the stack to keep the stack valid...
                    //
                    Debug.Assert(this._currentGroupAggregateInfo == aggregateInfo, "Aggregare info stack is corrupted."); 
                    this._currentGroupAggregateInfo = aggregateInfo.ContainingAggregate;
 
                    // 
                    // ...then validate and seal the aggregate info.
                    // Note that this operation may throw an EntitySqlException. 
                    //
                    aggregateInfo.ValidateAndComputeEvaluatingScopeRegion(this);
                });
        } 
        #endregion
    } 
 
    /// 
    /// Represents an utility for creating anonymous IDisposable implementations. 
    /// 
    internal class Disposer : IDisposable
    {
        private readonly Action _action; 

        internal Disposer(Action action) 
        { 
            Debug.Assert(action != null, "action != null");
            _action = action; 
        }

        public void Dispose()
        { 
            _action();
            GC.SuppressFinalize(this); 
        } 
    }
 
    internal enum GroupAggregateKind
    {
        None,
        ///  
        /// Inside of an aggregate function (Max, Min, etc).
        /// All range variables originating on the defining scope of this aggregate should yield . 
        ///  
        Function,
        ///  
        /// Inside of GROUPPARTITION expression.
        /// All range variables originating on the defining scope of this aggregate should yield .
        /// 
        Partition, 
        /// 
        /// Inside of a group key definition 
        /// All range variables originating on the defining scope of this aggregate should yield . 
        /// 
        GroupKey 
    }

    /// 
    /// Represents group aggregate information during aggregate construction/resolution. 
    /// 
    internal abstract class GroupAggregateInfo 
    { 
        protected GroupAggregateInfo(
            GroupAggregateKind aggregateKind, 
            AST.GroupAggregateExpr astNode,
            ErrorContext errCtx,
            GroupAggregateInfo containingAggregate,
            ScopeRegion definingScopeRegion) 
        {
            Debug.Assert(aggregateKind != GroupAggregateKind.None, "aggregateKind != GroupAggregateKind.None"); 
            Debug.Assert(errCtx != null, "errCtx != null"); 
            Debug.Assert(definingScopeRegion != null, "definingScopeRegion != null");
 
            AggregateKind = aggregateKind;
            AstNode = astNode;
            ErrCtx = errCtx;
            DefiningScopeRegion = definingScopeRegion; 
            SetContainingAggregate(containingAggregate);
        } 
 
        protected void AttachToAstNode(string aggregateName, TypeUsage resultType)
        { 
            Debug.Assert(AstNode != null, "AstNode must be set.");
            Debug.Assert(aggregateName != null && resultType != null, "aggregateName and aggregateDefinition must not be null.");
            Debug.Assert(AggregateName == null && AggregateStubExpression == null, "Cannot reattach.");
 
            AggregateName = aggregateName;
            AggregateStubExpression = resultType.Null(); 
 
            // Attach group aggregate info to the ast node.
            AstNode.AggregateInfo = this; 
        }

        internal void DetachFromAstNode()
        { 
            Debug.Assert(AstNode != null, "AstNode must be set.");
            AstNode.AggregateInfo = null; 
        } 

        ///  
        /// Updates referenced scope index of the aggregate.
        /// Function call is not allowed after  has been called.
        /// 
        internal void UpdateScopeIndex(int referencedScopeIndex, SemanticResolver sr) 
        {
            Debug.Assert(_evaluatingScopeRegion == null, "Can not update referenced scope index after _evaluatingScopeRegion have been computed."); 
 
            ScopeRegion referencedScopeRegion = sr.GetDefiningScopeRegion(referencedScopeIndex);
 
            if (_innermostReferencedScopeRegion == null ||
                _innermostReferencedScopeRegion.ScopeRegionIndex < referencedScopeRegion.ScopeRegionIndex)
            {
                _innermostReferencedScopeRegion = referencedScopeRegion; 
            }
        } 
 
        /// 
        /// Gets/sets the innermost referenced scope region of the current aggregate. 
        /// This property is used to save/restore the scope region value during a potentially throw-away attempt to
        /// convert an  as a collection function in the  method.
        /// Setting the value is not allowed after  has been called.
        ///  
        internal ScopeRegion InnermostReferencedScopeRegion
        { 
            get { return _innermostReferencedScopeRegion; } 
            set
            { 
                Debug.Assert(_evaluatingScopeRegion == null, "Can't change _innermostReferencedScopeRegion after _evaluatingScopeRegion has been initialized.");
                _innermostReferencedScopeRegion = value;
            }
        } 
        private ScopeRegion _innermostReferencedScopeRegion;
 
        ///  
        /// Validates the aggregate info and computes  property.
        /// Seals the aggregate info object (no more AddContainedAggregate(...), RemoveContainedAggregate(...) and UpdateScopeIndex(...) calls allowed). 
        /// 
        internal void ValidateAndComputeEvaluatingScopeRegion(SemanticResolver sr)
        {
            Debug.Assert(_evaluatingScopeRegion == null, "_evaluatingScopeRegion has already been initialized"); 
            //
            // If _innermostReferencedScopeRegion is null, it means the aggregate is not correlated (a constant value), 
            // so resolve it to the DefiningScopeRegion. 
            //
            _evaluatingScopeRegion = _innermostReferencedScopeRegion ?? DefiningScopeRegion; 

            if (!_evaluatingScopeRegion.IsAggregating)
            {
                // 
                // In some cases the found scope region does not aggregate (has no grouping). So adding the aggregate to that scope won't work.
                // In this situation we need to backtrack from the found region to the first inner region that performs aggregation. 
                // Example: 
                // select yy.cx, yy.cy, yy.cz
                // from {1, 2} as x cross apply (select zz.cx, zz.cy, zz.cz 
                //                               from {3, 4} as y cross apply (select Count(x) as cx, Count(y) as cy, Count(z) as cz
                //                                                             from {5, 6} as z) as zz
                //                              ) as yy
                // Note that Count aggregates cx and cy refer to scope regions that do aggregate. All three aggregates needs to be added to the only 
                // aggregating region - the innermost.
                // 
                int scopeRegionIndex = _evaluatingScopeRegion.ScopeRegionIndex; 
                _evaluatingScopeRegion = null;
                foreach (ScopeRegion innerSR in sr.ScopeRegions.Skip(scopeRegionIndex)) 
                {
                    if (innerSR.IsAggregating)
                    {
                        _evaluatingScopeRegion = innerSR; 
                        break;
                    } 
                } 
                if (_evaluatingScopeRegion == null)
                { 
                    throw EntityUtil.EntitySqlError(Strings.GroupVarNotFoundInScope);
                }
            }
 
            //
            // Validate all the contained aggregates for violation of the containment rule: 
            // None of the nested (contained) aggregates must be evaluating on a scope region that is 
            //      a. equal or inner to the evaluating scope of the current aggregate and
            //      b. equal or outer to the defining scope of the current aggregate. 
            //
            // Example of a disallowed query:
            //
            //      select 
            //              (select max(x + max(y))
            //               from {1} as y) 
            //      from {0} as x 
            //
            // Example of an allowed query where the ESR of the nested aggregate is outer to the ESR of the outer aggregate: 
            //
            //      select
            //              (select max(y + max(x))
            //               from {1} as y) 
            //      from {0} as x
            // 
            // Example of an allowed query where the ESR of the nested aggregate is inner to the DSR of the outer aggregate: 
            //
            //      select max(x + anyelement(select value max(y) from {1} as y)) 
            //      from {0} as x
            //
            Debug.Assert(_evaluatingScopeRegion.IsAggregating, "_evaluatingScopeRegion.IsAggregating must be true");
            Debug.Assert(_evaluatingScopeRegion.ScopeRegionIndex <= DefiningScopeRegion.ScopeRegionIndex, "_evaluatingScopeRegion must outer to the DefiningScopeRegion"); 
            ValidateContainedAggregates(_evaluatingScopeRegion.ScopeRegionIndex, DefiningScopeRegion.ScopeRegionIndex);
        } 
 
        /// 
        /// Recursively validates that  of all contained aggregates 
        /// is outside of the range of scope regions defined by  and .
        /// Throws in the case of violation.
        /// 
        private void ValidateContainedAggregates(int outerBoundaryScopeRegionIndex, int innerBoundaryScopeRegionIndex) 
        {
            if (_containedAggregates != null) 
            { 
                foreach (GroupAggregateInfo containedAggregate in _containedAggregates)
                { 
                    if (containedAggregate.EvaluatingScopeRegion.ScopeRegionIndex >= outerBoundaryScopeRegionIndex &&
                        containedAggregate.EvaluatingScopeRegion.ScopeRegionIndex <= innerBoundaryScopeRegionIndex)
                    {
                        int line, column; 
                        string currentAggregateInfo = EntitySqlException.FormatErrorContext(
                            ErrCtx.CommandText, 
                            ErrCtx.InputPosition, 
                            ErrCtx.ErrorContextInfo,
                            ErrCtx.UseContextInfoAsResourceIdentifier, 
                            out line, out column);

                        string nestedAggregateInfo = EntitySqlException.FormatErrorContext(
                            containedAggregate.ErrCtx.CommandText, 
                            containedAggregate.ErrCtx.InputPosition,
                            containedAggregate.ErrCtx.ErrorContextInfo, 
                            containedAggregate.ErrCtx.UseContextInfoAsResourceIdentifier, 
                            out line, out column);
 
                        throw EntityUtil.EntitySqlError(Strings.NestedAggregateCannotBeUsedInAggregate(nestedAggregateInfo, currentAggregateInfo));
                    }

                    // 
                    // We need to check the full subtree in order to catch this case:
                    //      select max(x + 
                    //                     anyelement(select max(y + 
                    //                                               anyelement(select value max(x)
                    //                                               from {2} as z)) 
                    //                                from {1} as y))
                    //      from {0} as x
                    //
                    containedAggregate.ValidateContainedAggregates(outerBoundaryScopeRegionIndex, innerBoundaryScopeRegionIndex); 
                }
            } 
        } 

        internal void SetContainingAggregate(GroupAggregateInfo containingAggregate) 
        {
            if (_containingAggregate != null)
            {
                // 
                // Aggregates in this query
                // 
                //      select value max(anyelement(select value max(b + max(a + anyelement(select value c1 
                //                                                                          from {2} as c group by c as c1)))
                //                                  from {1} as b group by b as b1)) 
                //
                //      from {0} as a group by a as a1
                //
                // are processed in the following steps: 
                // 1.  the outermost aggregate (max1) begins processing as a collection function;
                // 2.  the middle aggregate (max2) begins processing as a collection function; 
                // 3.  the innermost aggregate (max3) is processed as a collection function; 
                // 4.  max3 is reprocessed as an aggregate; it does not see any containing aggregates at this point, so it's not wired up;
                //     max3 is validated and sealed; 
                //     evaluating scope region for max3 is the outermost scope region, to which it gets assigned;
                //     max3 aggregate info object is attached to the corresponding AST node;
                // 5.  max2 completes processing as a collection function and begins processing as an aggregate;
                // 6.  max3 is reprocessed as an aggregate in the SemanticAnalyzer.TryConvertAsResolvedGroupAggregate(...) method, and 
                //     wired up to max2 as contained/containing;
                // 7.  max2 completes processing as an aggregate; 
                //     max2 is validated and sealed; 
                //     note that max2 does not see any containing aggregates at this point, so it's wired up only to max3;
                //     evaluating scope region for max2 is the middle scope region to which it gets assigned; 
                // 6.  middle scope region completes processing, yields a DbExpression and cleans up all aggregate info objects assigned to it (max2);
                //     max2 is detached from the corresponding AST node;
                //     at this point max3 is still assigned to the outermost scope region and still wired to the dropped max2 as containing/contained;
                // 7.  max1 completes processing as a collection function and begins processing as an aggregate; 
                // 8.  max2 is revisited and begins processing as a collection function (note that because the old aggregate info object for max2 was dropped
                //     and detached from the AST node in step 6, SemanticAnalyzer.TryConvertAsResolvedGroupAggregate(...) does not recognize max2 as an aggregate); 
                // 9.  max3 is recognized as an aggregate in the SemanticAnalyzer.TryConvertAsResolvedGroupAggregate(...) method; 
                //     max3 is rewired from the dropped max2 (step 6) to max1 as contained/containing, now max1 and max3 are wired as containing/contained;
                // 10. max2 completes processing as a collection function and begins processing as an aggregate; 
                //     max2 sees max1 as a containing aggregate and wires to it;
                // 11. max3 is reprocessed as resolved aggregate inside of TryConvertAsResolvedGroupAggregate(...) method;
                //     max3 is rewired from max1 to max2 as containing/contained aggregate;
                // 12. at this point max1 is wired to max2 and max2 is wired to max3, the tree is correct; 
                //
                // ... both max1 and max3 are assigned to the same scope for evaluation, this is detected and an error is reported; 
                // 

                // 
                // Remove this aggregate from the old containing aggregate before rewiring to the new parent.
                //
                _containingAggregate.RemoveContainedAggregate(this);
            } 

            // 
            // Accept the new parent and wire to it as a contained aggregate. 
            //
            _containingAggregate = containingAggregate; 
            if (_containingAggregate != null)
            {
                _containingAggregate.AddContainedAggregate(this);
            } 
        }
 
        ///  
        /// Function call is not allowed after  has been called.
        /// Adding new contained aggregate may invalidate the current aggregate. 
        /// 
        private void AddContainedAggregate(GroupAggregateInfo containedAggregate)
        {
            Debug.Assert(_evaluatingScopeRegion == null, "Can not add contained aggregate after _evaluatingScopeRegion have been computed."); 

            if (_containedAggregates == null) 
            { 
                _containedAggregates = new List();
            } 
            Debug.Assert(_containedAggregates.Contains(containedAggregate) == false, "containedAggregate is already registered");
            _containedAggregates.Add(containedAggregate);
        }
        private List _containedAggregates; 

        ///  
        /// Function call is _allowed_ after  has been called. 
        /// Removing contained aggregates cannot invalidate the current aggregate.
        /// 
        /// Consider the following query:
        ///
        ///   select value max(a + anyelement(select value max(b + max(a + anyelement(select value c1
        ///                                                                           from {2} as c group by c as c1))) 
        ///                                   from {1} as b group by b as b1))
        ///   from {0} as a group by a as a1 
        /// 
        /// Outer aggregate - max1, middle aggregate - max2, inner aggregate - max3.
        /// In this query after max1 have been processed as a collection function, max2 and max3 are wired as containing/contained. 
        /// There is a point later when max1 is processed as an aggregate, max2 is processed as a collection function and max3 is processed as
        /// an aggregate. Note that at this point the "aggregate" version of max2 is dropped and detached from the AST node when the middle scope region
        /// completes processing; also note that because evaluating scope region of max3 is the outer scope region, max3 aggregate info is still attached to
        /// the AST node and it is still wired to the dropped aggregate info object of max2. At this point max3 does not see new max2 as a containing aggregate, 
        /// and it rewires to max1, during this rewiring it needs to to remove itself from the old max2 and add itself to max1.
        /// The old max2 at this point is sealed, so the removal is performed on the sealed object. 
        ///  
        private void RemoveContainedAggregate(GroupAggregateInfo containedAggregate)
        { 
            Debug.Assert(_containedAggregates != null && _containedAggregates.Contains(containedAggregate), "_containedAggregates.Contains(containedAggregate)");

            _containedAggregates.Remove(containedAggregate);
        } 

        internal readonly GroupAggregateKind AggregateKind; 
 
        /// 
        /// Null when  is created for a group key processing. 
        /// 
        internal readonly AST.GroupAggregateExpr AstNode;

        internal readonly ErrorContext ErrCtx; 

        ///  
        /// Scope region that contains the aggregate expression. 
        /// 
        internal readonly ScopeRegion DefiningScopeRegion; 

        /// 
        /// Scope region that evaluates the aggregate expression.
        ///  
        internal ScopeRegion EvaluatingScopeRegion
        { 
            get 
            {
                // 
                // _evaluatingScopeRegion is initialized in the ValidateAndComputeEvaluatingScopeRegion(...) method.
                //
                Debug.Assert(_evaluatingScopeRegion != null, "_evaluatingScopeRegion is not initialized");
                return _evaluatingScopeRegion; 
            }
        } 
        private ScopeRegion _evaluatingScopeRegion; 

        ///  
        /// Parent aggregate expression that contains the current aggregate expression.
        /// May be null.
        /// 
        internal GroupAggregateInfo ContainingAggregate 
        {
            get { return _containingAggregate; } 
        } 
        private GroupAggregateInfo _containingAggregate;
 
        internal string AggregateName;
        internal DbNullExpression AggregateStubExpression;
    }
 
    internal sealed class FunctionAggregateInfo : GroupAggregateInfo
    { 
        internal FunctionAggregateInfo(AST.MethodExpr methodExpr, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) 
            : base(GroupAggregateKind.Function, methodExpr, errCtx, containingAggregate, definingScopeRegion)
        { 
            Debug.Assert(methodExpr != null, "methodExpr != null");
        }

        internal void AttachToAstNode(string aggregateName, DbAggregate aggregateDefinition) 
        {
            Debug.Assert(aggregateDefinition != null, "aggregateDefinition != null"); 
            base.AttachToAstNode(aggregateName, aggregateDefinition.ResultType); 
            AggregateDefinition = aggregateDefinition;
        } 

        internal DbAggregate AggregateDefinition;
    }
 
    internal sealed class GroupPartitionInfo : GroupAggregateInfo
    { 
        internal GroupPartitionInfo(AST.GroupPartitionExpr groupPartitionExpr, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) 
            : base(GroupAggregateKind.Partition, groupPartitionExpr, errCtx, containingAggregate, definingScopeRegion)
        { 
            Debug.Assert(groupPartitionExpr != null, "groupPartitionExpr != null");
        }

        internal void AttachToAstNode(string aggregateName, DbExpression aggregateDefinition) 
        {
            Debug.Assert(aggregateDefinition != null, "aggregateDefinition != null"); 
            base.AttachToAstNode(aggregateName, aggregateDefinition.ResultType); 
            AggregateDefinition = aggregateDefinition;
        } 

        internal DbExpression AggregateDefinition;
    }
 
    internal sealed class GroupKeyAggregateInfo : GroupAggregateInfo
    { 
        internal GroupKeyAggregateInfo(GroupAggregateKind aggregateKind, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) 
            : base(aggregateKind, null /* there is no AST.GroupAggregateExpression corresponding to the group key */, errCtx, containingAggregate, definingScopeRegion)
        { } 
    }

    internal abstract class InlineFunctionInfo
    { 
        internal InlineFunctionInfo(AST.FunctionDefinition functionDef, List parameters)
        { 
            FunctionDefAst = functionDef; 
            Parameters = parameters;
        } 

        internal readonly AST.FunctionDefinition FunctionDefAst;
        internal readonly List Parameters;
 
        internal abstract DbLambda GetLambda(SemanticResolver sr);
    } 
 
    internal sealed class ScopeRegion
    { 
        private readonly ScopeManager _scopeManager;

        internal ScopeRegion(ScopeManager scopeManager, int firstScopeIndex, int scopeRegionIndex)
        { 
            _scopeManager = scopeManager;
            _firstScopeIndex = firstScopeIndex; 
            _scopeRegionIndex = scopeRegionIndex; 
        }
 
        /// 
        /// First scope of the region.
        /// 
        internal int FirstScopeIndex 
        {
            get { return _firstScopeIndex; } 
        } 
        private readonly int _firstScopeIndex;
 
        /// 
        /// Index of the scope region.
        /// Outer scope regions have smaller index value than inner scope regions.
        ///  
        internal int ScopeRegionIndex
        { 
            get { return _scopeRegionIndex; } 
        }
        private readonly int _scopeRegionIndex; 

        /// 
        /// True if given scope is in the current scope region.
        ///  
        internal bool ContainsScope(int scopeIndex)
        { 
            return (scopeIndex >= _firstScopeIndex); 
        }
 
        /// 
        /// Marks current scope region as performing group/folding operation.
        /// 
        internal void EnterGroupOperation(DbExpressionBinding groupAggregateBinding) 
        {
            Debug.Assert(!IsAggregating, "Scope region group operation is not reentrant."); 
            _groupAggregateBinding = groupAggregateBinding; 
        }
        ///  
        /// Clears the  flag on the group scope.
        /// 
        internal void RollbackGroupOperation()
        { 
            Debug.Assert(IsAggregating, "Scope region must inside group operation in order to leave it.");
            _groupAggregateBinding = null; 
        } 
        /// 
        /// True when the scope region performs group/folding operation. 
        /// 
        internal bool IsAggregating
        {
            get { return _groupAggregateBinding != null; } 
        }
        internal DbExpressionBinding GroupAggregateBinding 
        { 
            get
            { 
                Debug.Assert(IsAggregating, "IsAggregating must be true.");
                return _groupAggregateBinding;
            }
        } 
        private DbExpressionBinding _groupAggregateBinding;
 
        ///  
        /// Returns list of group aggregates evaluated on the scope region.
        ///  
        internal List GroupAggregateInfos
        {
            get { return _groupAggregateInfos; }
        } 
        private List _groupAggregateInfos = new List();
 
        ///  
        /// Adds group aggregate name to the scope region.
        ///  
        internal void RegisterGroupAggregateName(string groupAggregateName)
        {
            Debug.Assert(!_groupAggregateNames.Contains(groupAggregateName), "!_groupAggregateNames.ContainsKey(groupAggregateName)");
            _groupAggregateNames.Add(groupAggregateName); 
        }
        internal bool ContainsGroupAggregate(string groupAggregateName) 
        { 
            return _groupAggregateNames.Contains(groupAggregateName);
        } 
        private HashSet _groupAggregateNames = new HashSet();

        /// 
        /// True if a recent expression resolution was correlated. 
        /// 
        internal bool WasResolutionCorrelated 
        { 
            get { return _wasResolutionCorrelated; }
            set { _wasResolutionCorrelated = value; } 
        }
        private bool _wasResolutionCorrelated = false;

        ///  
        /// Applies  to all scope entries in the current scope region.
        ///  
        internal void ApplyToScopeEntries(Action action) 
        {
            Debug.Assert(FirstScopeIndex <= _scopeManager.CurrentScopeIndex, "FirstScopeIndex <= CurrentScopeIndex"); 

            for (int i = FirstScopeIndex; i <= _scopeManager.CurrentScopeIndex; ++i)
            {
                foreach (KeyValuePair scopeEntry in _scopeManager.GetScopeByIndex(i)) 
                {
                    action(scopeEntry.Value); 
                } 
            }
        } 

        /// 
        /// Applies  to all scope entries in the current scope region.
        ///  
        internal void ApplyToScopeEntries(Func action)
        { 
            Debug.Assert(FirstScopeIndex <= _scopeManager.CurrentScopeIndex, "FirstScopeIndex <= CurrentScopeIndex"); 

            for (int i = FirstScopeIndex; i <= _scopeManager.CurrentScopeIndex; ++i) 
            {
                Scope scope = _scopeManager.GetScopeByIndex(i);
                List> updatedEntries = null;
                foreach (KeyValuePair scopeEntry in scope) 
                {
                    ScopeEntry newScopeEntry = action(scopeEntry.Value); 
                    Debug.Assert(newScopeEntry != null, "newScopeEntry != null"); 
                    if (scopeEntry.Value != newScopeEntry)
                    { 
                        if (updatedEntries == null)
                        {
                            updatedEntries = new List>();
                        } 
                        updatedEntries.Add(new KeyValuePair(scopeEntry.Key, newScopeEntry));
                    } 
                } 
                if (updatedEntries != null)
                { 
                    updatedEntries.ForEach((updatedScopeEntry) => scope.Replace(updatedScopeEntry.Key, updatedScopeEntry.Value));
                }
            }
        } 

        internal void RollbackAllScopes() 
        { 
            _scopeManager.RollbackToScope(FirstScopeIndex - 1);
        } 
    }

    /// 
    /// Represents a pair of types to avoid uncessary enumerations to split kvp elements 
    /// 
    internal sealed class Pair 
    { 
        internal Pair(L left, R right)
        { 
            Left = left;
            Right = right;
        }
 
        internal L Left;
        internal R Right; 
 
        internal KeyValuePair GetKVP()
        { 
            return new KeyValuePair(Left, Right);
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK