internal GroupPartitionInfo( GroupPartitionExpr groupPartitionExpr, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) : base(GroupAggregateKind.Partition, groupPartitionExpr, errCtx, containingAggregate, definingScopeRegion) { Debug.Assert(groupPartitionExpr != null, "groupPartitionExpr != null"); }
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); } }
internal GroupPartitionInfo( GroupPartitionExpr groupPartitionExpr, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) : base(GroupAggregateKind.Partition, groupPartitionExpr, errCtx, containingAggregate, definingScopeRegion) { DebugCheck.NotNull(groupPartitionExpr); }
/// <summary> /// Function call is _allowed_ after <see cref="ValidateAndComputeEvaluatingScopeRegion" /> 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. /// </summary> private void RemoveContainedAggregate(GroupAggregateInfo containedAggregate) { Debug.Assert( _containedAggregates != null && _containedAggregates.Contains(containedAggregate), "_containedAggregates.Contains(containedAggregate)"); _containedAggregates.Remove(containedAggregate); }
private void AddContainedAggregate(GroupAggregateInfo containedAggregate) { if (this._containedAggregates == null) { this._containedAggregates = new List <GroupAggregateInfo>(); } this._containedAggregates.Add(containedAggregate); }
internal GroupPartitionInfo( GroupPartitionExpr groupPartitionExpr, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) : base(GroupAggregateKind.Partition, (GroupAggregateExpr)groupPartitionExpr, errCtx, containingAggregate, definingScopeRegion) { }
internal FunctionAggregateInfo( MethodExpr methodExpr, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) : base(GroupAggregateKind.Function, (GroupAggregateExpr)methodExpr, errCtx, containingAggregate, definingScopeRegion) { }
internal GroupKeyAggregateInfo( GroupAggregateKind aggregateKind, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) : base(aggregateKind, (GroupAggregateExpr)null, errCtx, containingAggregate, definingScopeRegion) { }
private IDisposable EnterGroupAggregate(GroupAggregateInfo aggregateInfo) { this._currentGroupAggregateInfo = aggregateInfo; return((IDisposable) new Disposer((Action)(() => { this._currentGroupAggregateInfo = aggregateInfo.ContainingAggregate; aggregateInfo.ValidateAndComputeEvaluatingScopeRegion(this); }))); }
/// <summary> /// Function call is not allowed after <see cref="ValidateAndComputeEvaluatingScopeRegion" /> has been called. /// Adding new contained aggregate may invalidate the current aggregate. /// </summary> 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 <GroupAggregateInfo>(); } Debug.Assert(_containedAggregates.Contains(containedAggregate) == false, "containedAggregate is already registered"); _containedAggregates.Add(containedAggregate); }
protected GroupAggregateInfo( GroupAggregateKind aggregateKind, GroupAggregateExpr astNode, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) { this.AggregateKind = aggregateKind; this.AstNode = astNode; this.ErrCtx = errCtx; this.DefiningScopeRegion = definingScopeRegion; this.SetContainingAggregate(containingAggregate); }
internal void SetContainingAggregate(GroupAggregateInfo containingAggregate) { if (this._containingAggregate != null) { this._containingAggregate.RemoveContainedAggregate(this); } this._containingAggregate = containingAggregate; if (this._containingAggregate == null) { return; } this._containingAggregate.AddContainedAggregate(this); }
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); }
protected GroupAggregateInfo( GroupAggregateKind aggregateKind, GroupAggregateExpr astNode, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) { Debug.Assert(aggregateKind != GroupAggregateKind.None, "aggregateKind != GroupAggregateKind.None"); DebugCheck.NotNull(errCtx); DebugCheck.NotNull(definingScopeRegion); AggregateKind = aggregateKind; AstNode = astNode; ErrCtx = errCtx; DefiningScopeRegion = definingScopeRegion; SetContainingAggregate(containingAggregate); }
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(_currentGroupAggregateInfo == aggregateInfo, "Aggregare info stack is corrupted."); _currentGroupAggregateInfo = aggregateInfo.ContainingAggregate; // // ...then validate and seal the aggregate info. // Note that this operation may throw an EntitySqlException. // aggregateInfo.ValidateAndComputeEvaluatingScopeRegion(this); })); }
internal FunctionAggregateInfo( MethodExpr methodExpr, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) : base(GroupAggregateKind.Function, methodExpr, errCtx, containingAggregate, definingScopeRegion) { DebugCheck.NotNull(methodExpr); }
private void RemoveContainedAggregate(GroupAggregateInfo containedAggregate) { this._containedAggregates.Remove(containedAggregate); }
internal FunctionAggregateInfo( MethodExpr methodExpr, ErrorContext errCtx, GroupAggregateInfo containingAggregate, ScopeRegion definingScopeRegion) : base(GroupAggregateKind.Function, methodExpr, errCtx, containingAggregate, definingScopeRegion) { Debug.Assert(methodExpr != null, "methodExpr != null"); }
// <summary> // Function call is not allowed after <see cref="ValidateAndComputeEvaluatingScopeRegion" /> has been called. // Adding new contained aggregate may invalidate the current aggregate. // </summary> 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<GroupAggregateInfo>(); } Debug.Assert(_containedAggregates.Contains(containedAggregate) == false, "containedAggregate is already registered"); _containedAggregates.Add(containedAggregate); }
// <summary> // Function call is _allowed_ after <see cref="ValidateAndComputeEvaluatingScopeRegion" /> 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. // </summary> private void RemoveContainedAggregate(GroupAggregateInfo containedAggregate) { Debug.Assert( _containedAggregates != null && _containedAggregates.Contains(containedAggregate), "_containedAggregates.Contains(containedAggregate)"); _containedAggregates.Remove(containedAggregate); }