public override void Visit(VarDefOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { this.VisitDefault(n); System.Data.Entity.Core.Query.InternalTrees.Node child0 = n.Child0; Op op1 = child0.Op; GroupAggregateVarInfo groupAggregateVarInfo; System.Data.Entity.Core.Query.InternalTrees.Node templateNode; bool isUnnested; if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar(child0, true, this._command, this._groupAggregateVarInfoManager, out groupAggregateVarInfo, out templateNode, out isUnnested)) { this._groupAggregateVarInfoManager.Add(op.Var, groupAggregateVarInfo, templateNode, isUnnested); } else { if (op1.OpType != OpType.NewRecord) { return; } NewRecordOp newRecordOp = (NewRecordOp)op1; for (int index = 0; index < child0.Children.Count; ++index) { if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar(child0.Children[index], true, this._command, this._groupAggregateVarInfoManager, out groupAggregateVarInfo, out templateNode, out isUnnested)) { this._groupAggregateVarInfoManager.Add(op.Var, groupAggregateVarInfo, templateNode, isUnnested, (EdmMember)newRecordOp.Properties[index]); } } } }
// <summary> // Determines whether the var or a property of the var (if the var is defined as a NewRecord) // is defined exclusively over a single group aggregate. If so, it registers it as such with the // group aggregate var info manager. // </summary> public override void Visit(VarDefOp op, Node n) { VisitDefault(n); var definingNode = n.Child0; var definingNodeOp = definingNode.Op; GroupAggregateVarInfo referencedVarInfo; Node templateNode; bool isUnnested; if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar( definingNode, true, _command, _groupAggregateVarInfoManager, out referencedVarInfo, out templateNode, out isUnnested)) { _groupAggregateVarInfoManager.Add(op.Var, referencedVarInfo, templateNode, isUnnested); } else if (definingNodeOp.OpType == OpType.NewRecord) { var newRecordOp = (NewRecordOp)definingNodeOp; for (var i = 0; i < definingNode.Children.Count; i++) { var argumentNode = definingNode.Children[i]; if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar( argumentNode, true, _command, _groupAggregateVarInfoManager, out referencedVarInfo, out templateNode, out isUnnested)) { _groupAggregateVarInfoManager.Add(op.Var, referencedVarInfo, templateNode, isUnnested, newRecordOp.Properties[i]); } } } }
public override void Visit(FunctionOp op, Node n) { VisitDefault(n); if (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n)) { return; } if (n.Children.Count > 1) { return; } GroupAggregateVarInfo referencedGroupAggregateVarInfo; Node templateNode; bool isUnnested; if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar( n.Child0, false, _command, _groupAggregateVarInfoManager, out referencedGroupAggregateVarInfo, out templateNode, out isUnnested) && (isUnnested || AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, referencedGroupAggregateVarInfo.GroupAggregateVar))) { referencedGroupAggregateVarInfo.CandidateAggregateNodes.Add(new KeyValuePair <Node, List <Node> >(n, new List <Node> { templateNode })); } }
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); }
public override void Visit(FunctionOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { this.VisitDefault(n); if (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n)) { return; } System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(n.Children.Count == 1, "Aggregate Function must have one argument"); System.Data.Entity.Core.Query.InternalTrees.Node child0 = n.Child0; GroupAggregateVarInfo groupAggregateVarInfo; System.Data.Entity.Core.Query.InternalTrees.Node templateNode; bool isUnnested; if (!GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar(n.Child0, false, this._command, this._groupAggregateVarInfoManager, out groupAggregateVarInfo, out templateNode, out isUnnested) || !isUnnested && !AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, groupAggregateVarInfo.GroupAggregateVar)) { return; } groupAggregateVarInfo.CandidateAggregateNodes.Add(new KeyValuePair <System.Data.Entity.Core.Query.InternalTrees.Node, System.Data.Entity.Core.Query.InternalTrees.Node>(n, templateNode)); }
public override void Visit(FunctionOp op, Node n) { VisitDefault(n); if (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n)) { return; } PlanCompiler.Assert(n.Children.Count == 1, "Aggregate Function must have one argument"); var argumentNode = n.Child0; GroupAggregateVarInfo referencedGroupAggregateVarInfo; Node templateNode; bool isUnnested; if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar( n.Child0, false, _command, _groupAggregateVarInfoManager, out referencedGroupAggregateVarInfo, out templateNode, out isUnnested) && (isUnnested || AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, referencedGroupAggregateVarInfo.GroupAggregateVar))) { referencedGroupAggregateVarInfo.CandidateAggregateNodes.Add(new KeyValuePair <Node, Node>(n, templateNode)); } }
// <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 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; }