/// <summary>
        ///     Add an entry that the given property of the given var is a computation represented
        ///     by the computationTemplate over the var represented by the given groupAggregateVarInfo
        /// </summary>
        internal void Add(
            Var var, GroupAggregateVarInfo groupAggregateVarInfo, Node computationTemplate, bool isUnnested, EdmMember property)
        {
            if (property == null)
            {
                Add(var, groupAggregateVarInfo, computationTemplate, isUnnested);
                return;
            }
            if (_groupAggregateVarRelatedVarPropertyToInfo == null)
            {
                _groupAggregateVarRelatedVarPropertyToInfo = new Dictionary <Var, Dictionary <EdmMember, GroupAggregateVarRefInfo> >();
            }
            Dictionary <EdmMember, GroupAggregateVarRefInfo> varPropertyDictionary;

            if (!_groupAggregateVarRelatedVarPropertyToInfo.TryGetValue(var, out varPropertyDictionary))
            {
                varPropertyDictionary = new Dictionary <EdmMember, GroupAggregateVarRefInfo>();
                _groupAggregateVarRelatedVarPropertyToInfo.Add(var, varPropertyDictionary);
            }
            varPropertyDictionary.Add(property, new GroupAggregateVarRefInfo(groupAggregateVarInfo, computationTemplate, isUnnested));

            // Note: The following line is not necessary with the current usage pattern, this method is
            // never called with a new groupAggregateVarInfo thus it is a no-op.
            _groupAggregateVarInfos.Add(groupAggregateVarInfo);
        }
Exemple #2
0
 internal void Add(
     Var var,
     GroupAggregateVarInfo groupAggregateVarInfo,
     System.Data.Entity.Core.Query.InternalTrees.Node computationTemplate,
     bool isUnnested,
     EdmMember property)
 {
     if (property == null)
     {
         this.Add(var, groupAggregateVarInfo, computationTemplate, isUnnested);
     }
     else
     {
         if (this._groupAggregateVarRelatedVarPropertyToInfo == null)
         {
             this._groupAggregateVarRelatedVarPropertyToInfo = new Dictionary <Var, Dictionary <EdmMember, GroupAggregateVarRefInfo> >();
         }
         Dictionary <EdmMember, GroupAggregateVarRefInfo> dictionary;
         if (!this._groupAggregateVarRelatedVarPropertyToInfo.TryGetValue(var, out dictionary))
         {
             dictionary = new Dictionary <EdmMember, GroupAggregateVarRefInfo>();
             this._groupAggregateVarRelatedVarPropertyToInfo.Add(var, dictionary);
         }
         dictionary.Add(property, new GroupAggregateVarRefInfo(groupAggregateVarInfo, computationTemplate, isUnnested));
         this._groupAggregateVarInfos.Add(groupAggregateVarInfo);
     }
 }
Exemple #3
0
        private System.Data.Entity.Core.Query.InternalTrees.Node TranslateOverGroupAggregateVar(
            Var var,
            EdmMember property)
        {
            GroupAggregateVarRefInfo groupAggregateVarRefInfo;
            EdmMember prop;

            if (this._groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(var, out groupAggregateVarRefInfo))
            {
                prop = property;
            }
            else
            {
                if (!this._groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(var, property, out groupAggregateVarRefInfo))
                {
                    return((System.Data.Entity.Core.Query.InternalTrees.Node)null);
                }
                prop = (EdmMember)null;
            }
            if (this._targetGroupAggregateVarInfo == null)
            {
                this._targetGroupAggregateVarInfo = groupAggregateVarRefInfo.GroupAggregateVarInfo;
                this._isUnnested = groupAggregateVarRefInfo.IsUnnested;
            }
            else if (this._targetGroupAggregateVarInfo != groupAggregateVarRefInfo.GroupAggregateVarInfo || this._isUnnested != groupAggregateVarRefInfo.IsUnnested)
            {
                return((System.Data.Entity.Core.Query.InternalTrees.Node)null);
            }
            System.Data.Entity.Core.Query.InternalTrees.Node node = groupAggregateVarRefInfo.Computation;
            if (prop != null)
            {
                node = this._command.CreateNode((Op)this._command.CreatePropertyOp(prop), node);
            }
            return(node);
        }
        private void TryProcessCandidate(
            KeyValuePair<Node, Node> candidate,
            GroupAggregateVarInfo groupAggregateVarInfo)
        {
            IList<Node> functionAncestors;
            IList<Node> groupByAncestors;
            var definingGroupNode = groupAggregateVarInfo.DefiningGroupNode;
            FindPathsToLeastCommonAncestor(candidate.Key, definingGroupNode, out functionAncestors, out groupByAncestors);

            //Check whether all ancestors of the GroupByInto node are of type that we support propagating through
            if (!AreAllNodesSupportedForPropagation(groupByAncestors))
            {
                return;
            }

            //Add the function to the group by node
            var definingGroupOp = (GroupByIntoOp)definingGroupNode.Op;
            PlanCompiler.Assert(definingGroupOp.Inputs.Count == 1, "There should be one input var to GroupByInto at this stage");
            var inputVar = definingGroupOp.Inputs.First;
            var functionOp = (FunctionOp)candidate.Key.Op;

            //
            // Remap the template from referencing the groupAggregate var to reference the input to
            // the group by into
            //
            var argumentNode = OpCopier.Copy(m_command, candidate.Value);
            var dictionary = new Dictionary<Var, Var>(1);
            dictionary.Add(groupAggregateVarInfo.GroupAggregateVar, inputVar);
            var remapper = new VarRemapper(m_command, dictionary);
            remapper.RemapSubtree(argumentNode);

            var newFunctionDefiningNode = m_command.CreateNode(
                m_command.CreateAggregateOp(functionOp.Function, false),
                argumentNode);

            Var newFunctionVar;
            var varDefNode = m_command.CreateVarDefNode(newFunctionDefiningNode, out newFunctionVar);

            // Add the new aggregate to the list of aggregates
            definingGroupNode.Child2.Children.Add(varDefNode);
            var groupByOp = (GroupByIntoOp)definingGroupNode.Op;
            groupByOp.Outputs.Set(newFunctionVar);

            //Propagate the new var throught the ancestors of the GroupByInto
            for (var i = 0; i < groupByAncestors.Count; i++)
            {
                var groupByAncestor = groupByAncestors[i];
                if (groupByAncestor.Op.OpType
                    == OpType.Project)
                {
                    var ancestorProjectOp = (ProjectOp)groupByAncestor.Op;
                    ancestorProjectOp.Outputs.Set(newFunctionVar);
                }
            }

            //Update the functionNode
            candidate.Key.Op = m_command.CreateVarRefOp(newFunctionVar);
            candidate.Key.Children.Clear();
        }
Exemple #5
0
 internal void Add(
     Var var,
     GroupAggregateVarInfo groupAggregateVarInfo,
     System.Data.Entity.Core.Query.InternalTrees.Node computationTemplate,
     bool isUnnested)
 {
     this._groupAggregateVarRelatedVarToInfo.Add(var, new GroupAggregateVarRefInfo(groupAggregateVarInfo, computationTemplate, isUnnested));
     this._groupAggregateVarInfos.Add(groupAggregateVarInfo);
 }
Exemple #6
0
 internal GroupAggregateVarRefInfo(
     GroupAggregateVarInfo groupAggregateVarInfo,
     Node computation,
     bool isUnnested)
 {
     this._groupAggregateVarInfo = groupAggregateVarInfo;
     this._computation           = computation;
     this._isUnnested            = isUnnested;
 }
Exemple #7
0
        public static bool TryTranslateOverGroupAggregateVar(
            System.Data.Entity.Core.Query.InternalTrees.Node subtree,
            bool isVarDefinition,
            Command command,
            GroupAggregateVarInfoManager groupAggregateVarInfoManager,
            out GroupAggregateVarInfo groupAggregateVarInfo,
            out System.Data.Entity.Core.Query.InternalTrees.Node templateNode,
            out bool isUnnested)
        {
            GroupAggregateVarComputationTranslator computationTranslator = new GroupAggregateVarComputationTranslator(command, groupAggregateVarInfoManager);

            System.Data.Entity.Core.Query.InternalTrees.Node n = subtree;
            SoftCastOp softCastOp1 = (SoftCastOp)null;

            if (n.Op.OpType == OpType.SoftCast)
            {
                softCastOp1 = (SoftCastOp)n.Op;
                n           = n.Child0;
            }
            bool flag;

            if (n.Op.OpType == OpType.Collect)
            {
                templateNode = computationTranslator.VisitCollect(n);
                flag         = true;
            }
            else
            {
                templateNode = computationTranslator.VisitNode(n);
                flag         = false;
            }
            groupAggregateVarInfo = computationTranslator._targetGroupAggregateVarInfo;
            isUnnested            = computationTranslator._isUnnested;
            if (computationTranslator._targetGroupAggregateVarInfo == null || templateNode == null)
            {
                return(false);
            }
            if (softCastOp1 != null)
            {
                SoftCastOp softCastOp2 = flag || !isVarDefinition && AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, computationTranslator._targetGroupAggregateVarInfo.GroupAggregateVar) ? command.CreateSoftCastOp(TypeHelpers.GetEdmType <CollectionType>(softCastOp1.Type).TypeUsage) : softCastOp1;
                templateNode = command.CreateNode((Op)softCastOp2, templateNode);
            }
            return(true);
        }
        private void TryProcessCandidate(
            KeyValuePair <System.Data.Entity.Core.Query.InternalTrees.Node, System.Data.Entity.Core.Query.InternalTrees.Node> candidate,
            GroupAggregateVarInfo groupAggregateVarInfo)
        {
            System.Data.Entity.Core.Query.InternalTrees.Node         definingGroupNode = groupAggregateVarInfo.DefiningGroupNode;
            IList <System.Data.Entity.Core.Query.InternalTrees.Node> ancestors1;
            IList <System.Data.Entity.Core.Query.InternalTrees.Node> ancestors2;

            this.FindPathsToLeastCommonAncestor(candidate.Key, definingGroupNode, out ancestors1, out ancestors2);
            if (!AggregatePushdown.AreAllNodesSupportedForPropagation(ancestors2))
            {
                return;
            }
            GroupByIntoOp op1 = (GroupByIntoOp)definingGroupNode.Op;

            System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(op1.Inputs.Count == 1, "There should be one input var to GroupByInto at this stage");
            Var        first = op1.Inputs.First;
            FunctionOp op2   = (FunctionOp)candidate.Key.Op;

            System.Data.Entity.Core.Query.InternalTrees.Node subTree = OpCopier.Copy(this.m_command, candidate.Value);
            new VarRemapper(this.m_command, new Dictionary <Var, Var>(1)
            {
                {
                    groupAggregateVarInfo.GroupAggregateVar,
                    first
                }
            }).RemapSubtree(subTree);
            Var computedVar;

            System.Data.Entity.Core.Query.InternalTrees.Node varDefNode = this.m_command.CreateVarDefNode(this.m_command.CreateNode((Op)this.m_command.CreateAggregateOp(op2.Function, false), subTree), out computedVar);
            definingGroupNode.Child2.Children.Add(varDefNode);
            ((GroupByBaseOp)definingGroupNode.Op).Outputs.Set(computedVar);
            for (int index = 0; index < ancestors2.Count; ++index)
            {
                System.Data.Entity.Core.Query.InternalTrees.Node node = ancestors2[index];
                if (node.Op.OpType == OpType.Project)
                {
                    ((ProjectOp)node.Op).Outputs.Set(computedVar);
                }
            }
            candidate.Key.Op = (Op)this.m_command.CreateVarRefOp(computedVar);
            candidate.Key.Children.Clear();
        }
        // <summary>
        // (1) If the given var or the given property of the given var are defined over a group aggregate var,
        // (2) and if that group aggregate var matches the var represented by represented by _targetGroupAggregateVarInfo
        // if any
        // it returns the corresponding translation over the group aggregate var. Also, if _targetGroupAggregateVarInfo
        // is not set, it sets it to the group aggregate var representing the referenced var.
        // </summary>
        private Node TranslateOverGroupAggregateVar(Var var, EdmMember property)
        {
            GroupAggregateVarRefInfo groupAggregateVarRefInfo;
            EdmMember localProperty;

            if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(var, out groupAggregateVarRefInfo))
            {
                localProperty = property;
            }
            else if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(var, property, out groupAggregateVarRefInfo))
            {
                localProperty = null;
            }
            else
            {
                return(null);
            }

            if (_targetGroupAggregateVarInfo == null)
            {
                _targetGroupAggregateVarInfo = groupAggregateVarRefInfo.GroupAggregateVarInfo;
                _isUnnested = groupAggregateVarRefInfo.IsUnnested;
            }
            else if (_targetGroupAggregateVarInfo != groupAggregateVarRefInfo.GroupAggregateVarInfo ||
                     _isUnnested != groupAggregateVarRefInfo.IsUnnested)
            {
                return(null);
            }

            var computationTemplate = groupAggregateVarRefInfo.Computation;

            if (localProperty != null)
            {
                computationTemplate = _command.CreateNode(_command.CreatePropertyOp(localProperty), computationTemplate);
            }
            return(computationTemplate);
        }
        // <summary>
        // Add an entry that the given property of the given var is a computation represented
        // by the computationTemplate over the var represented by the given groupAggregateVarInfo
        // </summary>
        internal void Add(
            Var var, GroupAggregateVarInfo groupAggregateVarInfo, Node computationTemplate, bool isUnnested, EdmMember property)
        {
            if (property == null)
            {
                Add(var, groupAggregateVarInfo, computationTemplate, isUnnested);
                return;
            }
            if (_groupAggregateVarRelatedVarPropertyToInfo == null)
            {
                _groupAggregateVarRelatedVarPropertyToInfo = new Dictionary<Var, Dictionary<EdmMember, GroupAggregateVarRefInfo>>();
            }
            Dictionary<EdmMember, GroupAggregateVarRefInfo> varPropertyDictionary;
            if (!_groupAggregateVarRelatedVarPropertyToInfo.TryGetValue(var, out varPropertyDictionary))
            {
                varPropertyDictionary = new Dictionary<EdmMember, GroupAggregateVarRefInfo>();
                _groupAggregateVarRelatedVarPropertyToInfo.Add(var, varPropertyDictionary);
            }
            varPropertyDictionary.Add(property, new GroupAggregateVarRefInfo(groupAggregateVarInfo, computationTemplate, isUnnested));

            // Note: The following line is not necessary with the current usage pattern, this method is 
            // never called with a new groupAggregateVarInfo thus it is a no-op.
            _groupAggregateVarInfos.Add(groupAggregateVarInfo);
        }
 /// <summary>
 /// Public constructor
 /// </summary>
 /// <param name="groupAggregateVarInfo"></param>
 /// <param name="computation"></param>
 internal GroupAggregateVarRefInfo(GroupAggregateVarInfo groupAggregateVarInfo, Node computation, bool isUnnested)
 {
     _groupAggregateVarInfo = groupAggregateVarInfo;
     _computation = computation;
     _isUnnested = isUnnested;
 }
        private Node VisitCollect(Node n)
        {
            //Make sure the only children are projects over unnest
            var currentNode = n.Child0;
            var constantDefinitions = new Dictionary<Var, Node>();
            while (currentNode.Child0.Op.OpType
                   == OpType.Project)
            {
                currentNode = currentNode.Child0;
                //Visit the VarDefListOp child
                if (VisitDefault(currentNode.Child1) == null)
                {
                    return null;
                }
                foreach (var definitionNode in currentNode.Child1.Children)
                {
                    if (IsConstant(definitionNode.Child0))
                    {
                        constantDefinitions.Add(((VarDefOp)definitionNode.Op).Var, definitionNode.Child0);
                    }
                }
            }

            if (currentNode.Child0.Op.OpType
                != OpType.Unnest)
            {
                return null;
            }

            // Handle the unnest
            var unnestOp = (UnnestOp)currentNode.Child0.Op;
            GroupAggregateVarRefInfo groupAggregateVarRefInfo;
            if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(unnestOp.Var, out groupAggregateVarRefInfo))
            {
                if (_targetGroupAggregateVarInfo == null)
                {
                    _targetGroupAggregateVarInfo = groupAggregateVarRefInfo.GroupAggregateVarInfo;
                }
                else if (_targetGroupAggregateVarInfo != groupAggregateVarRefInfo.GroupAggregateVarInfo)
                {
                    return null;
                }
                if (!_isUnnested)
                {
                    return null;
                }
            }
            else
            {
                return null;
            }

            var physicalProjectOp = (PhysicalProjectOp)n.Child0.Op;
            PlanCompiler.Assert(physicalProjectOp.Outputs.Count == 1, "Physical project should only have one output at this stage");
            var outputVar = physicalProjectOp.Outputs[0];

            var computationTemplate = TranslateOverGroupAggregateVar(outputVar, null);
            if (computationTemplate != null)
            {
                _isUnnested = true;
                return computationTemplate;
            }

            Node constantDefinitionNode;
            if (constantDefinitions.TryGetValue(outputVar, out constantDefinitionNode))
            {
                _isUnnested = true;
                return constantDefinitionNode;
            }
            return null;
        }
 /// <summary>
 ///     Add an entry that var is a computation represented by the computationTemplate
 ///     over the var represented by the given groupAggregateVarInfo
 /// </summary>
 internal void Add(Var var, GroupAggregateVarInfo groupAggregateVarInfo, Node computationTemplate, bool isUnnested)
 {
     _groupAggregateVarRelatedVarToInfo.Add(
         var, new GroupAggregateVarRefInfo(groupAggregateVarInfo, computationTemplate, isUnnested));
     _groupAggregateVarInfos.Add(groupAggregateVarInfo);
 }
        /// <summary>
        ///     (1) If the given var or the given property of the given var are defined over a group aggregate var,
        ///     (2) and if that group aggregate var matches the var represented by represented by _targetGroupAggregateVarInfo
        ///     if any
        ///     it returns the corresponding translation over the group aggregate var. Also, if _targetGroupAggregateVarInfo
        ///     is not set, it sets it to the group aggregate var representing the referenced var.
        /// </summary>
        /// <param name="var"> </param>
        /// <param name="property"> </param>
        /// <returns> </returns>
        private Node TranslateOverGroupAggregateVar(Var var, EdmMember property)
        {
            GroupAggregateVarRefInfo groupAggregateVarRefInfo;
            EdmMember localProperty;
            if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(var, out groupAggregateVarRefInfo))
            {
                localProperty = property;
            }
            else if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(var, property, out groupAggregateVarRefInfo))
            {
                localProperty = null;
            }
            else
            {
                return null;
            }

            if (_targetGroupAggregateVarInfo == null)
            {
                _targetGroupAggregateVarInfo = groupAggregateVarRefInfo.GroupAggregateVarInfo;
                _isUnnested = groupAggregateVarRefInfo.IsUnnested;
            }
            else if (_targetGroupAggregateVarInfo != groupAggregateVarRefInfo.GroupAggregateVarInfo
                     || _isUnnested != groupAggregateVarRefInfo.IsUnnested)
            {
                return null;
            }

            var computationTemplate = groupAggregateVarRefInfo.Computation;
            if (localProperty != null)
            {
                computationTemplate = _command.CreateNode(_command.CreatePropertyOp(localProperty), computationTemplate);
            }
            return computationTemplate;
        }
        // <summary>
        // Try to produce an equivalent tree to the input subtree, over a single group aggregate variable.
        // Such translation can only be produced if all external references of the input subtree are to a
        // single group aggregate var, or to vars that are can be translated over that single group
        // aggregate var
        // </summary>
        // <param name="subtree"> The input subtree </param>
        // <param name="groupAggregateVarInfo"> The groupAggregateVarInfo over which the input subtree can be translated </param>
        // <param name="templateNode"> A tree that is equvalent to the input tree, but over the group aggregate variable represented by the groupAggregetVarInfo </param>
        // <returns> True, if the translation can be done, false otherwise </returns>
        public static bool TryTranslateOverGroupAggregateVar(
            Node subtree,
            bool isVarDefinition,
            Command command,
            GroupAggregateVarInfoManager groupAggregateVarInfoManager,
            out GroupAggregateVarInfo groupAggregateVarInfo,
            out Node templateNode,
            out bool isUnnested)
        {
            var handler = new GroupAggregateVarComputationTranslator(command, groupAggregateVarInfoManager);

            var        inputNode  = subtree;
            SoftCastOp softCastOp = null;
            bool       isCollect;

            if (inputNode.Op.OpType
                == OpType.SoftCast)
            {
                softCastOp = (SoftCastOp)inputNode.Op;
                inputNode  = inputNode.Child0;
            }

            if (inputNode.Op.OpType
                == OpType.Collect)
            {
                templateNode = handler.VisitCollect(inputNode);
                isCollect    = true;
            }
            else
            {
                templateNode = handler.VisitNode(inputNode);
                isCollect    = false;
            }

            groupAggregateVarInfo = handler._targetGroupAggregateVarInfo;
            isUnnested            = handler._isUnnested;

            if (handler._targetGroupAggregateVarInfo == null ||
                templateNode == null)
            {
                return(false);
            }
            if (softCastOp != null)
            {
                SoftCastOp newSoftCastOp;
                //
                // The type needs to be fixed only if the unnesting happened during this translation.
                // That can be recognized by these two cases:
                //      1) if the input node was a collect, or
                //      2) if the input did not represent a var definition, but a function aggregate argument and
                //              the template is VarRef of a group aggregate var.
                //
                if (isCollect
                    ||
                    !isVarDefinition &&
                    AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, handler._targetGroupAggregateVarInfo.GroupAggregateVar))
                {
                    newSoftCastOp = command.CreateSoftCastOp(TypeHelpers.GetEdmType <CollectionType>(softCastOp.Type).TypeUsage);
                }
                else
                {
                    newSoftCastOp = softCastOp;
                }
                templateNode = command.CreateNode(newSoftCastOp, templateNode);
            }
            return(true);
        }
        private Node VisitCollect(Node n)
        {
            //Make sure the only children are projects over unnest
            var currentNode         = n.Child0;
            var constantDefinitions = new Dictionary <Var, Node>();

            while (currentNode.Child0.Op.OpType
                   == OpType.Project)
            {
                currentNode = currentNode.Child0;
                //Visit the VarDefListOp child
                if (VisitDefault(currentNode.Child1) == null)
                {
                    return(null);
                }
                foreach (var definitionNode in currentNode.Child1.Children)
                {
                    if (IsConstant(definitionNode.Child0))
                    {
                        constantDefinitions.Add(((VarDefOp)definitionNode.Op).Var, definitionNode.Child0);
                    }
                }
            }

            if (currentNode.Child0.Op.OpType
                != OpType.Unnest)
            {
                return(null);
            }

            // Handle the unnest
            var unnestOp = (UnnestOp)currentNode.Child0.Op;
            GroupAggregateVarRefInfo groupAggregateVarRefInfo;

            if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(unnestOp.Var, out groupAggregateVarRefInfo))
            {
                if (_targetGroupAggregateVarInfo == null)
                {
                    _targetGroupAggregateVarInfo = groupAggregateVarRefInfo.GroupAggregateVarInfo;
                }
                else if (_targetGroupAggregateVarInfo != groupAggregateVarRefInfo.GroupAggregateVarInfo)
                {
                    return(null);
                }
                if (!_isUnnested)
                {
                    return(null);
                }
            }
            else
            {
                return(null);
            }

            var physicalProjectOp = (PhysicalProjectOp)n.Child0.Op;

            PlanCompiler.Assert(physicalProjectOp.Outputs.Count == 1, "Physical project should only have one output at this stage");
            var outputVar = physicalProjectOp.Outputs[0];

            var computationTemplate = TranslateOverGroupAggregateVar(outputVar, null);

            if (computationTemplate != null)
            {
                _isUnnested = true;
                return(computationTemplate);
            }

            Node constantDefinitionNode;

            if (constantDefinitions.TryGetValue(outputVar, out constantDefinitionNode))
            {
                _isUnnested = true;
                return(constantDefinitionNode);
            }
            return(null);
        }
Exemple #17
0
        private System.Data.Entity.Core.Query.InternalTrees.Node VisitCollect(System.Data.Entity.Core.Query.InternalTrees.Node n)
        {
            System.Data.Entity.Core.Query.InternalTrees.Node child0 = n.Child0;
            Dictionary <Var, System.Data.Entity.Core.Query.InternalTrees.Node> dictionary = new Dictionary <Var, System.Data.Entity.Core.Query.InternalTrees.Node>();

            while (child0.Child0.Op.OpType == OpType.Project)
            {
                child0 = child0.Child0;
                if (this.VisitDefault(child0.Child1) == null)
                {
                    return((System.Data.Entity.Core.Query.InternalTrees.Node)null);
                }
                foreach (System.Data.Entity.Core.Query.InternalTrees.Node child in child0.Child1.Children)
                {
                    if (GroupAggregateVarComputationTranslator.IsConstant(child.Child0))
                    {
                        dictionary.Add(((VarDefOp)child.Op).Var, child.Child0);
                    }
                }
            }
            if (child0.Child0.Op.OpType != OpType.Unnest)
            {
                return((System.Data.Entity.Core.Query.InternalTrees.Node)null);
            }
            GroupAggregateVarRefInfo groupAggregateVarRefInfo;

            if (!this._groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(((UnnestOp)child0.Child0.Op).Var, out groupAggregateVarRefInfo))
            {
                return((System.Data.Entity.Core.Query.InternalTrees.Node)null);
            }
            if (this._targetGroupAggregateVarInfo == null)
            {
                this._targetGroupAggregateVarInfo = groupAggregateVarRefInfo.GroupAggregateVarInfo;
            }
            else if (this._targetGroupAggregateVarInfo != groupAggregateVarRefInfo.GroupAggregateVarInfo)
            {
                return((System.Data.Entity.Core.Query.InternalTrees.Node)null);
            }
            if (!this._isUnnested)
            {
                return((System.Data.Entity.Core.Query.InternalTrees.Node)null);
            }
            PhysicalProjectOp op = (PhysicalProjectOp)n.Child0.Op;

            System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(op.Outputs.Count == 1, "Physical project should only have one output at this stage");
            Var output = op.Outputs[0];

            System.Data.Entity.Core.Query.InternalTrees.Node node1 = this.TranslateOverGroupAggregateVar(output, (EdmMember)null);
            if (node1 != null)
            {
                this._isUnnested = true;
                return(node1);
            }
            System.Data.Entity.Core.Query.InternalTrees.Node node2;
            if (!dictionary.TryGetValue(output, out node2))
            {
                return((System.Data.Entity.Core.Query.InternalTrees.Node)null);
            }
            this._isUnnested = true;
            return(node2);
        }
        /// <summary>
        ///     Try to produce an equivalent tree to the input subtree, over a single group aggregate variable.
        ///     Such translation can only be produced if all external references of the input subtree are to a
        ///     single group aggregate var, or to vars that are can be translated over that single group
        ///     aggregate var
        /// </summary>
        /// <param name="subtree"> The input subtree </param>
        /// <param name="isVarDefinition"> </param>
        /// <param name="command"> </param>
        /// <param name="groupAggregateVarInfoManager"> </param>
        /// <param name="groupAggregateVarInfo"> The groupAggregateVarInfo over which the input subtree can be translated </param>
        /// <param name="templateNode"> A tree that is equvalent to the input tree, but over the group aggregate variable represented by the groupAggregetVarInfo </param>
        /// <param name="isUnnested"> </param>
        /// <returns> True, if the translation can be done, false otherwise </returns>
        public static bool TryTranslateOverGroupAggregateVar(
            Node subtree,
            bool isVarDefinition,
            Command command,
            GroupAggregateVarInfoManager groupAggregateVarInfoManager,
            out GroupAggregateVarInfo groupAggregateVarInfo,
            out Node templateNode,
            out bool isUnnested)
        {
            var handler = new GroupAggregateVarComputationTranslator(command, groupAggregateVarInfoManager);

            var inputNode = subtree;
            SoftCastOp softCastOp = null;
            bool isCollect;
            if (inputNode.Op.OpType
                == OpType.SoftCast)
            {
                softCastOp = (SoftCastOp)inputNode.Op;
                inputNode = inputNode.Child0;
            }

            if (inputNode.Op.OpType
                == OpType.Collect)
            {
                templateNode = handler.VisitCollect(inputNode);
                isCollect = true;
            }
            else
            {
                templateNode = handler.VisitNode(inputNode);
                isCollect = false;
            }

            groupAggregateVarInfo = handler._targetGroupAggregateVarInfo;
            isUnnested = handler._isUnnested;

            if (handler._targetGroupAggregateVarInfo == null
                || templateNode == null)
            {
                return false;
            }
            if (softCastOp != null)
            {
                SoftCastOp newSoftCastOp;
                // 
                // The type needs to be fixed only if the unnesting happened during this translation.
                // That can be recognized by these two cases: 
                //      1) if the input node was a collect, or 
                //      2) if the input did not represent a var definition, but a function aggregate argument and 
                //              the template is VarRef of a group aggregate var.
                //
                if (isCollect
                    ||
                    !isVarDefinition
                    && AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, handler._targetGroupAggregateVarInfo.GroupAggregateVar))
                {
                    newSoftCastOp = command.CreateSoftCastOp(TypeHelpers.GetEdmType<CollectionType>(softCastOp.Type).TypeUsage);
                }
                else
                {
                    newSoftCastOp = softCastOp;
                }
                templateNode = command.CreateNode(newSoftCastOp, templateNode);
            }
            return true;
        }
        private void TryProcessCandidate(
            KeyValuePair <Node, Node> candidate,
            GroupAggregateVarInfo groupAggregateVarInfo)
        {
            IList <Node> functionAncestors;
            IList <Node> groupByAncestors;
            var          definingGroupNode = groupAggregateVarInfo.DefiningGroupNode;

            FindPathsToLeastCommonAncestor(candidate.Key, definingGroupNode, out functionAncestors, out groupByAncestors);

            //Check whether all ancestors of the GroupByInto node are of type that we support propagating through
            if (!AreAllNodesSupportedForPropagation(groupByAncestors))
            {
                return;
            }

            //Add the function to the group by node
            var definingGroupOp = (GroupByIntoOp)definingGroupNode.Op;

            PlanCompiler.Assert(definingGroupOp.Inputs.Count == 1, "There should be one input var to GroupByInto at this stage");
            var inputVar   = definingGroupOp.Inputs.First;
            var functionOp = (FunctionOp)candidate.Key.Op;

            //
            // Remap the template from referencing the groupAggregate var to reference the input to
            // the group by into
            //
            var argumentNode = OpCopier.Copy(m_command, candidate.Value);
            var dictionary   = new Dictionary <Var, Var>(1);

            dictionary.Add(groupAggregateVarInfo.GroupAggregateVar, inputVar);
            var remapper = new VarRemapper(m_command, dictionary);

            remapper.RemapSubtree(argumentNode);

            var newFunctionDefiningNode = m_command.CreateNode(
                m_command.CreateAggregateOp(functionOp.Function, false),
                argumentNode);

            Var newFunctionVar;
            var varDefNode = m_command.CreateVarDefNode(newFunctionDefiningNode, out newFunctionVar);

            // Add the new aggregate to the list of aggregates
            definingGroupNode.Child2.Children.Add(varDefNode);
            var groupByOp = (GroupByIntoOp)definingGroupNode.Op;

            groupByOp.Outputs.Set(newFunctionVar);

            //Propagate the new var throught the ancestors of the GroupByInto
            for (var i = 0; i < groupByAncestors.Count; i++)
            {
                var groupByAncestor = groupByAncestors[i];
                if (groupByAncestor.Op.OpType
                    == OpType.Project)
                {
                    var ancestorProjectOp = (ProjectOp)groupByAncestor.Op;
                    ancestorProjectOp.Outputs.Set(newFunctionVar);
                }
            }

            //Update the functionNode
            candidate.Key.Op = m_command.CreateVarRefOp(newFunctionVar);
            candidate.Key.Children.Clear();
        }
 // <summary>
 // Add an entry that var is a computation represented by the computationTemplate
 // over the var represented by the given groupAggregateVarInfo
 // </summary>
 internal void Add(Var var, GroupAggregateVarInfo groupAggregateVarInfo, Node computationTemplate, bool isUnnested)
 {
     _groupAggregateVarRelatedVarToInfo.Add(
         var, new GroupAggregateVarRefInfo(groupAggregateVarInfo, computationTemplate, isUnnested));
     _groupAggregateVarInfos.Add(groupAggregateVarInfo);
 }