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