/// <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); }
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); } }
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(); }
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); }
internal GroupAggregateVarRefInfo( GroupAggregateVarInfo groupAggregateVarInfo, Node computation, bool isUnnested) { this._groupAggregateVarInfo = groupAggregateVarInfo; this._computation = computation; this._isUnnested = isUnnested; }
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); }
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); }