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