Esempio n. 1
0
 private bool TryScopeLookup(string key, out ScopeEntry scopeEntry, out int scopeIndex)
 {
     scopeEntry = (ScopeEntry)null;
     scopeIndex = -1;
     for (int currentScopeIndex = this.CurrentScopeIndex; currentScopeIndex >= 0; --currentScopeIndex)
     {
         if (this._scopeManager.GetScopeByIndex(currentScopeIndex).TryLookup(key, out scopeEntry))
         {
             scopeIndex = currentScopeIndex;
             return(true);
         }
     }
     return(false);
 }
Esempio n. 2
0
        private DbExpression GetExpressionFromScopeEntry(
            ScopeEntry scopeEntry,
            int scopeIndex,
            string varName,
            ErrorContext errCtx)
        {
            DbExpression dbExpression = scopeEntry.GetExpression(varName, errCtx);

            if (this._currentGroupAggregateInfo != null)
            {
                ScopeRegion definingScopeRegion = this.GetDefiningScopeRegion(scopeIndex);
                if (definingScopeRegion.ScopeRegionIndex <= this._currentGroupAggregateInfo.DefiningScopeRegion.ScopeRegionIndex)
                {
                    this._currentGroupAggregateInfo.UpdateScopeIndex(scopeIndex, this);
                    IGroupExpressionExtendedInfo expressionExtendedInfo = scopeEntry as IGroupExpressionExtendedInfo;
                    if (expressionExtendedInfo != null)
                    {
                        GroupAggregateInfo groupAggregateInfo = this._currentGroupAggregateInfo;
                        while (groupAggregateInfo != null && groupAggregateInfo.DefiningScopeRegion.ScopeRegionIndex >= definingScopeRegion.ScopeRegionIndex && groupAggregateInfo.DefiningScopeRegion.ScopeRegionIndex != definingScopeRegion.ScopeRegionIndex)
                        {
                            groupAggregateInfo = groupAggregateInfo.ContainingAggregate;
                        }
                        if (groupAggregateInfo == null || groupAggregateInfo.DefiningScopeRegion.ScopeRegionIndex < definingScopeRegion.ScopeRegionIndex)
                        {
                            groupAggregateInfo = this._currentGroupAggregateInfo;
                        }
                        switch (groupAggregateInfo.AggregateKind)
                        {
                        case GroupAggregateKind.Function:
                            if (expressionExtendedInfo.GroupVarBasedExpression != null)
                            {
                                dbExpression = expressionExtendedInfo.GroupVarBasedExpression;
                                break;
                            }
                            break;

                        case GroupAggregateKind.Partition:
                            if (expressionExtendedInfo.GroupAggBasedExpression != null)
                            {
                                dbExpression = expressionExtendedInfo.GroupAggBasedExpression;
                                break;
                            }
                            break;
                        }
                    }
                }
            }
            return(dbExpression);
        }
        /// <summary>
        ///     Performs scope lookup returning the scope entry and its index.
        /// </summary>
        private bool TryScopeLookup(string key, out ScopeEntry scopeEntry, out int scopeIndex)
        {
            scopeEntry = null;
            scopeIndex = -1;

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

            return(false);
        }
Esempio n. 4
0
 internal void ApplyToScopeEntries(Func <ScopeEntry, ScopeEntry> action)
 {
     for (int firstScopeIndex = this.FirstScopeIndex; firstScopeIndex <= this._scopeManager.CurrentScopeIndex; ++firstScopeIndex)
     {
         Scope scope = this._scopeManager.GetScopeByIndex(firstScopeIndex);
         List <KeyValuePair <string, ScopeEntry> > ts = (List <KeyValuePair <string, ScopeEntry> >)null;
         foreach (KeyValuePair <string, ScopeEntry> keyValuePair in scope)
         {
             ScopeEntry scopeEntry = action(keyValuePair.Value);
             if (keyValuePair.Value != scopeEntry)
             {
                 if (ts == null)
                 {
                     ts = new List <KeyValuePair <string, ScopeEntry> >();
                 }
                 ts.Add(new KeyValuePair <string, ScopeEntry>(keyValuePair.Key, scopeEntry));
             }
         }
         if (ts != null)
         {
             ts.Each <KeyValuePair <string, ScopeEntry> >((Action <KeyValuePair <string, ScopeEntry> >)(updatedScopeEntry => scope.Replace(updatedScopeEntry.Key, updatedScopeEntry.Value)));
         }
     }
 }
        /// <summary>
        ///     Returns the appropriate expression from a given scope entry.
        ///     May return null for scope entries like <see cref="InvalidGroupInputRefScopeEntry" />.
        /// </summary>
        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.
            //

            var 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.
                //
                var 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);

                    var 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);
        }