/// <summary> /// We perform the following simple transformation for CaseOps. If every single /// then/else expression in the CaseOp is equivalent, then we can simply replace /// the Op with the first then/expression. Specifically, /// case when w1 then t1 when w2 then t2 ... when wn then tn else e end /// => t1 /// assuming that t1 is equivalent to t2 is equivalent to ... to e /// </summary> /// <param name="context"> Rule Processing context </param> /// <param name="caseOpNode"> The current subtree for the CaseOp </param> /// <param name="newNode"> the (possibly) modified subtree </param> /// <returns> true, if we performed any transformations </returns> private static bool ProcessSimplifyCase(RuleProcessingContext context, Node caseOpNode, out Node newNode) { var caseOp = (CaseOp)caseOpNode.Op; newNode = caseOpNode; // // Can I collapse the entire case-expression into a single expression - yes, // if all the then/else clauses are the same expression // if (ProcessSimplifyCase_Collapse(caseOpNode, out newNode)) { return true; } // // Can I remove any unnecessary when-then pairs ? // if (ProcessSimplifyCase_EliminateWhenClauses(context, caseOp, caseOpNode, out newNode)) { return true; } // Nothing else I can think of return false; }
internal Node ReMap(Node node, Dictionary<Var, Node> varMap) { PlanCompiler.Assert(node.Op.IsScalarOp, "Expected a scalarOp: Found " + Dump.AutoString.ToString(node.Op.OpType)); // Replace varRefOps by the corresponding expression in the map, if any if (node.Op.OpType == OpType.VarRef) { var varRefOp = node.Op as VarRefOp; Node newNode = null; if (varMap.TryGetValue(varRefOp.Var, out newNode)) { newNode = Copy(newNode); return newNode; } else { return node; } } // Simply process the result of the children. for (var i = 0; i < node.Children.Count; i++) { node.Children[i] = ReMap(node.Children[i], varMap); } // We may have changed something deep down Command.RecomputeNodeInfo(node); return node; }
/// <summary> /// Basic constructor /// </summary> /// <param name="pattern"> The pattern to look for </param> /// <param name="processDelegate"> The callback to invoke when such a pattern is identified </param> internal PatternMatchRule(Node pattern, ProcessNodeDelegate processDelegate) : base(pattern.Op.OpType, processDelegate) { Debug.Assert(pattern != null, "null pattern"); Debug.Assert(pattern.Op != null, "null pattern Op"); m_pattern = pattern; }
/// <summary> /// If the DistinctOp includes all all the keys of the input, than it is unnecessary. /// Distinct (X, distinct_keys) -> Project( X, distinct_keys) where distinct_keys includes all keys of X. /// </summary> /// <param name="context"> Rule processing context </param> /// <param name="n"> current subtree </param> /// <param name="newNode"> transformed subtree </param> /// <returns> transformation status </returns> private static bool ProcessDistinctOpOfKeys(RuleProcessingContext context, Node n, out Node newNode) { var command = context.Command; var nodeInfo = command.GetExtendedNodeInfo(n.Child0); var op = (DistinctOp)n.Op; //If we know the keys of the input and the list of distinct keys includes them all, omit the distinct if (!nodeInfo.Keys.NoKeys && op.Keys.Subsumes(nodeInfo.Keys.KeyVars)) { var newOp = command.CreateProjectOp(op.Keys); //Create empty vardef list var varDefListOp = command.CreateVarDefListOp(); var varDefListNode = command.CreateNode(varDefListOp); newNode = command.CreateNode(newOp, n.Child0, varDefListNode); return true; } //Otherwise return the node as is newNode = n; return false; }
internal static Node Copy(Command cmd, Node n, out VarMap varMap) { var oc = new OpCopier(cmd); var newNode = oc.CopyNode(n); varMap = oc.m_varMap; return newNode; }
// <summary> // Convert a // SingleRowOp(X) => X // if X produces at most one row // </summary> // <param name="context"> Rule Processing context </param> // <param name="singleRowNode"> Current subtree </param> // <param name="newNode"> transformed subtree </param> // <returns> Transformation status </returns> private static bool ProcessSingleRowOpOverAnything(RuleProcessingContext context, Node singleRowNode, out Node newNode) { newNode = singleRowNode; var trc = (TransformationRulesContext)context; var childNodeInfo = context.Command.GetExtendedNodeInfo(singleRowNode.Child0); // If the input to this Op can produce at most one row, then we don't need the // singleRowOp - simply return the input if (childNodeInfo.MaxRows <= RowCount.One) { newNode = singleRowNode.Child0; return true; } // // if the current node is a FilterOp, then try and determine if the FilterOp // produces one row at most // if (singleRowNode.Child0.Op.OpType == OpType.Filter) { var predicate = new Predicate(context.Command, singleRowNode.Child0.Child1); if (predicate.SatisfiesKey(childNodeInfo.Keys.KeyVars, childNodeInfo.Definitions)) { childNodeInfo.MaxRows = RowCount.One; newNode = singleRowNode.Child0; return true; } } // we couldn't do anything return false; }
private static bool ApplyRulesToNode( RuleProcessingContext context, ReadOnlyCollection<ReadOnlyCollection<Rule>> rules, Node currentNode, out Node newNode) { newNode = currentNode; // Apply any pre-rule delegates context.PreProcess(currentNode); foreach (var r in rules[(int)currentNode.Op.OpType]) { if (!r.Match(currentNode)) { continue; } // Did the rule modify the subtree? if (r.Apply(context, currentNode, out newNode)) { // The node has changed; don't try to apply any more rules context.PostProcess(newNode, r); return true; } else { Debug.Assert(newNode == currentNode, "Liar! This rule should have returned 'true'"); } } context.PostProcess(currentNode, null); return false; }
/// <summary> /// Basic constructor /// </summary> /// <param name="pattern"> The pattern to look for </param> /// <param name="processDelegate"> The callback to invoke when such a pattern is identified </param> internal PatternMatchRule(Node pattern, ProcessNodeDelegate processDelegate) : base(pattern.Op.OpType, processDelegate) { DebugCheck.NotNull(pattern); DebugCheck.NotNull(pattern.Op); m_pattern = pattern; }
/// <summary> /// Compute the hash value for this node /// </summary> internal override void ComputeHashValue(Command cmd, Node n) { base.ComputeHashValue(cmd, n); m_hashValue = (m_hashValue << 4) ^ GetHashValue(Definitions); m_hashValue = (m_hashValue << 4) ^ GetHashValue(Keys.KeyVars); return; }
/// <summary> /// Process a SetOp when one of the inputs is an emptyset. /// /// An emptyset is represented by a Filter(X, ConstantPredicate) /// where the ConstantPredicate has a value of "false" /// /// The general rules are /// UnionAll(X, EmptySet) => X /// UnionAll(EmptySet, X) => X /// Intersect(EmptySet, X) => EmptySet /// Intersect(X, EmptySet) => EmptySet /// Except(EmptySet, X) => EmptySet /// Except(X, EmptySet) => X /// /// These rules then translate into /// UnionAll: return the non-empty input /// Intersect: return the empty input /// Except: return the "left" input /// </summary> /// <param name="context"> Rule processing context </param> /// <param name="setOpNode"> the current setop tree </param> /// <param name="filterNodeIndex"> Index of the filter node in the setop </param> /// <param name="newNode"> transformed subtree </param> /// <returns> transformation status </returns> private static bool ProcessSetOpOverEmptySet(RuleProcessingContext context, Node setOpNode, out Node newNode) { var leftChildIsEmptySet = context.Command.GetExtendedNodeInfo(setOpNode.Child0).MaxRows == RowCount.Zero; var rightChildIsEmptySet = context.Command.GetExtendedNodeInfo(setOpNode.Child1).MaxRows == RowCount.Zero; if (!leftChildIsEmptySet && !rightChildIsEmptySet) { newNode = setOpNode; return false; } int indexToReturn; var setOp = (SetOp)setOpNode.Op; if (!rightChildIsEmptySet && setOp.OpType == OpType.UnionAll || !leftChildIsEmptySet && setOp.OpType == OpType.Intersect) { indexToReturn = 1; } else { indexToReturn = 0; } newNode = setOpNode.Children[indexToReturn]; var trc = (TransformationRulesContext)context; foreach (var kv in setOp.VarMap[indexToReturn]) { trc.AddVarMapping(kv.Key, kv.Value); } return true; }
/// <summary> /// Determines whether any var from a given list of keys is referenced by any of defining node's right relatives, /// with the exception of the relatives brunching at the given targetJoinNode. /// </summary> /// <param name="keys"> A list of vars to check for </param> /// <param name="definingNode"> The node considered to be the defining node </param> /// <param name="targetJoinNode"> The relatives branching at this node are skipped </param> /// <returns> False, only it can determine that not a single var from a given list of keys is referenced by any of defining node's right relatives, with the exception of the relatives brunching at the given targetJoinNode. </returns> internal bool HasKeyReferences(VarVec keys, Node definingNode, Node targetJoinNode) { var currentChild = definingNode; Node parent; var continueUp = true; while (continueUp & m_nodeToParentMap.TryGetValue(currentChild, out parent)) { if (parent != targetJoinNode) { // Check the parent if (HasVarReferencesShallow(parent, keys, m_nodeToSiblingNumber[currentChild], out continueUp)) { return true; } //Check all the siblings to the right for (var i = m_nodeToSiblingNumber[currentChild] + 1; i < parent.Children.Count; i++) { if (parent.Children[i].GetNodeInfo(m_command).ExternalReferences.Overlaps(keys)) { return true; } } } currentChild = parent; } return false; }
protected override Node VisitDefault(Node n) { var negated = _negated; switch (n.Op.OpType) { case OpType.Not: _negated = !_negated; n = base.VisitDefault(n); break; case OpType.Or: n = HandleOr(n); break; case OpType.And: n = base.VisitDefault(n); break; case OpType.EQ: _negated = false; n = HandleEQ(n, negated); break; case OpType.NE: n = HandleNE(n); break; default: _negated = false; n = base.VisitDefault(n); break; } _negated = negated; return n; }
private bool Match(Node pattern, Node original) { if (pattern.Op.OpType == OpType.Leaf) { return true; } if (pattern.Op.OpType != original.Op.OpType) { return false; } if (pattern.Children.Count != original.Children.Count) { return false; } for (var i = 0; i < pattern.Children.Count; i++) { if (!Match(pattern.Children[i], original.Children[i])) { return false; } } return true; }
/// <summary> /// Visit the children of this Node /// </summary> /// <param name="n"> The Node that references the Op </param> protected virtual void VisitChildren(Node n) { foreach (var chi in n.Children) { VisitNode(chi); } }
/// <summary> /// Visit the children of this Node. but in reverse order /// </summary> /// <param name="n"> The current node </param> protected virtual void VisitChildrenReverse(Node n) { for (var i = n.Children.Count - 1; i >= 0; i--) { VisitNode(n.Children[i]); } }
// <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]); } } } }
private Node HandleOr(Node n) { // Check for the pattern '(varRef IS NULL) OR expression'. var isNullNode = n.Child0.Op.OpType == OpType.IsNull ? n.Child0 : null; if (isNullNode == null || isNullNode.Child0.Op.OpType != OpType.VarRef) { return base.VisitDefault(n); } // Mark 'variable' as not nullable while 'expression' is visited. Var variable = ((VarRefOp)isNullNode.Child0.Op).Var; var nullable = _variableNullabilityTable[variable]; _variableNullabilityTable[variable] = false; n.Child1 = VisitNode(n.Child1); _variableNullabilityTable[variable] = nullable; return n; }
// <summary> // Update vars in just this node (and not the entire subtree) // Does *not* recompute the nodeinfo - there are at least some consumers of this // function that do not want the recomputation - transformation rules, for example // </summary> // <param name="node"> current node </param> internal virtual void RemapNode(Node node) { if (m_varMap.Count == 0) { return; } VisitNode(node); }
protected static void AssertArity(Node n) { if (n.Op.Arity != Op.ArityVarying) { AssertArity(n, n.Op.Arity); } }
/// <summary> /// Equivalent to OpCopier.Copy, only in addition it keeps track of the defining subtrees /// of collection vars defined in the subtree rooted at the copy of the input node n. /// </summary> /// <param name="cmd"></param> /// <param name="n"></param> /// <param name="varMap"></param> /// <param name="newCollectionVarDefinitions"></param> /// <returns></returns> internal static Node Copy(Command cmd, Node n, out VarMap varMap, out Dictionary<Var, Node> newCollectionVarDefinitions) { var oc = new OpCopierTrackingCollectionVars(cmd); var newNode = oc.CopyNode(n); varMap = oc.m_varMap; newCollectionVarDefinitions = oc.m_newCollectionVarDefinitions; return newNode; }
/// <summary> /// Pull up keys (if possible) for the given node /// </summary> /// <param name="node"> node to pull up keys for </param> /// <returns> Keys for the node </returns> internal KeyVec GetKeys(Node node) { var nodeInfo = node.GetExtendedNodeInfo(m_command); if (nodeInfo.Keys.NoKeys) { VisitNode(node); } return nodeInfo.Keys; }
// List of columns of this table that are nullable (and must have nulls pruned out) #endregion #region constructors /// <summary> /// Basic constructor /// </summary> /// <param name="id">node id</param> /// <param name="node">scan table node</param> internal AugmentedTableNode(int id, Node node) : base(id, node) { var scanTableOp = (ScanTableOp)node.Op; m_table = scanTableOp.Table; LastVisibleId = id; m_replacementTable = this; m_newLocationId = id; }
/// <summary> /// Build Project(select 1 from child). /// </summary> private Node BuildDummyProjectForExists(Node child) { Var newVar; var projectNode = m_command.BuildProject( child, m_command.CreateNode(m_command.CreateInternalConstantOp(m_command.IntegerType, 1)), out newVar); return projectNode; }
/// <summary> /// Tracks the information that the given node is a parent of its children (one level only) /// </summary> internal void AddChildren(Node parent) { for (var i = 0; i < parent.Children.Count; i++) { //We do not use add on purpose, we may be updating a child's parent after join elimination in a subtree m_nodeToParentMap[parent.Children[i]] = parent; m_nodeToSiblingNumber[parent.Children[i]] = i; } }
/// <summary> /// Determines whether the given node is a VarRef over the given var /// </summary> /// <param name="node"> </param> /// <param name="var"> </param> /// <returns> </returns> internal static bool IsVarRefOverGivenVar(Node node, Var var) { if (node.Op.OpType != OpType.VarRef) { return false; } return ((VarRefOp)node.Op).Var == var; }
/// <summary> /// Translate Exists(X) into Exists(select 1 from X) /// </summary> public override Node Visit(ExistsOp op, Node n) { VisitChildren(n); // Build up a dummy project node over the input n.Child0 = BuildDummyProjectForExists(n.Child0); return n; }
/// <summary> /// Convert Filter(Filter(X, p1), p2) => Filter(X, (p1 and p2)) /// </summary> /// <param name="context"> rule processing context </param> /// <param name="filterNode"> FilterOp node </param> /// <param name="newNode"> modified subtree </param> /// <returns> transformed subtree </returns> private static bool ProcessFilterOverFilter(RuleProcessingContext context, Node filterNode, out Node newNode) { var newAndNode = context.Command.CreateNode( context.Command.CreateConditionalOp(OpType.And), filterNode.Child0.Child1, filterNode.Child1); newNode = context.Command.CreateNode(context.Command.CreateFilterOp(), filterNode.Child0.Child0, newAndNode); return true; }
/// <summary> /// Converts a Project(Project(X, c1,...), d1,...) => /// Project(X, d1', d2'...) /// where d1', d2' etc. are the "mapped" versions of d1, d2 etc. /// </summary> /// <param name="context"> Rule processing context </param> /// <param name="projectNode"> Current ProjectOp node </param> /// <param name="newNode"> modified subtree </param> /// <returns> Transformation status </returns> private static bool ProcessProjectOverProject(RuleProcessingContext context, Node projectNode, out Node newNode) { newNode = projectNode; var projectOp = (ProjectOp)projectNode.Op; var varDefListNode = projectNode.Child1; var subProjectNode = projectNode.Child0; var subProjectOp = (ProjectOp)subProjectNode.Op; var trc = (TransformationRulesContext)context; // If any of the defining expressions is not a scalar op tree, then simply // quit var varRefMap = new Dictionary<Var, int>(); foreach (var varDefNode in varDefListNode.Children) { if (!trc.IsScalarOpTree(varDefNode.Child0, varRefMap)) { return false; } } var varMap = trc.GetVarMap(subProjectNode.Child1, varRefMap); if (varMap == null) { return false; } // create a new varDefList node... var newVarDefListNode = trc.Command.CreateNode(trc.Command.CreateVarDefListOp()); // Remap any local definitions, I have foreach (var varDefNode in varDefListNode.Children) { // update the defining expression varDefNode.Child0 = trc.ReMap(varDefNode.Child0, varMap); trc.Command.RecomputeNodeInfo(varDefNode); newVarDefListNode.Children.Add(varDefNode); } // Now, pull up any definitions of the subProject that I publish myself var projectNodeInfo = trc.Command.GetExtendedNodeInfo(projectNode); foreach (var chi in subProjectNode.Child1.Children) { var varDefOp = (VarDefOp)chi.Op; if (projectNodeInfo.Definitions.IsSet(varDefOp.Var)) { newVarDefListNode.Children.Add(chi); } } // // now that we have remapped all our computed vars, simply bypass the subproject // node // projectNode.Child0 = subProjectNode.Child0; projectNode.Child1 = newVarDefListNode; return true; }
protected Node AddSubqueryToParentRelOp(Var outputVar, Node subquery) { var ancestor = FindRelOpAncestor(); PlanCompiler.Assert(ancestor != null, "no ancestors found?"); AddSubqueryToRelOpNode(ancestor, subquery); subquery = m_command.CreateNode(m_command.CreateVarRefOp(outputVar)); return subquery; }
/// <summary> /// basic constructor /// </summary> /// <param name="id"> current node id </param> /// <param name="node"> the join node </param> /// <param name="leftChild"> left side of the join (innerJoin, LOJ and FOJ only) </param> /// <param name="rightChild"> right side of the join </param> /// <param name="leftVars"> left-side equijoin vars </param> /// <param name="rightVars"> right-side equijoin vars </param> /// <param name="otherPredicate"> any remaining predicate </param> internal AugmentedJoinNode( int id, Node node, AugmentedNode leftChild, AugmentedNode rightChild, List<ColumnVar> leftVars, List<ColumnVar> rightVars, Node otherPredicate) : this(id, node, new List<AugmentedNode>(new[] { leftChild, rightChild })) { m_otherPredicate = otherPredicate; m_rightVars = rightVars; m_leftVars = leftVars; }
private static bool PreservesNulls(System.Data.Entity.Core.Query.InternalTrees.Node simplePredNode, VarVec tableColumns) { switch (simplePredNode.Op.OpType) { case OpType.GT: case OpType.GE: case OpType.LE: case OpType.LT: case OpType.EQ: case OpType.NE: VarRefOp op1 = simplePredNode.Child0.Op as VarRefOp; if (op1 != null && tableColumns.IsSet(op1.Var)) { return(false); } VarRefOp op2 = simplePredNode.Child1.Op as VarRefOp; return(op2 == null || !tableColumns.IsSet(op2.Var)); case OpType.Like: ConstantBaseOp op3 = simplePredNode.Child1.Op as ConstantBaseOp; if (op3 == null || op3.OpType == OpType.Null) { return(true); } VarRefOp op4 = simplePredNode.Child0.Op as VarRefOp; return(op4 == null || !tableColumns.IsSet(op4.Var)); case OpType.Not: if (simplePredNode.Child0.Op.OpType != OpType.IsNull) { return(true); } VarRefOp op5 = simplePredNode.Child0.Child0.Op as VarRefOp; if (op5 != null) { return(!tableColumns.IsSet(op5.Var)); } return(true); default: return(true); } }
private static bool ProcessComparisonsOverConstant( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node node, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { newNode = node; System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(node.Op.OpType == OpType.EQ || node.Op.OpType == OpType.NE, "unexpected comparison op type?"); bool?nullable = new bool?(node.Child0.Op.IsEquivalent(node.Child1.Op)); if (!nullable.HasValue) { return(false); } bool flag = node.Op.OpType == OpType.EQ ? nullable.Value : !nullable.Value; ConstantPredicateOp constantPredicateOp = context.Command.CreateConstantPredicateOp(flag); newNode = context.Command.CreateNode((Op)constantPredicateOp); return(true); }
private static bool ProcessSimplifyCase_Collapse(System.Data.Entity.Core.Query.InternalTrees.Node caseOpNode, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { newNode = caseOpNode; System.Data.Entity.Core.Query.InternalTrees.Node child1 = caseOpNode.Child1; System.Data.Entity.Core.Query.InternalTrees.Node child = caseOpNode.Children[caseOpNode.Children.Count - 1]; if (!child1.IsEquivalent(child)) { return(false); } for (int index = 3; index < caseOpNode.Children.Count - 1; index += 2) { if (!caseOpNode.Children[index].IsEquivalent(child1)) { return(false); } } newNode = child1; 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(); }
protected override System.Data.Entity.Core.Query.InternalTrees.Node VisitJoinOp( JoinBaseOp op, System.Data.Entity.Core.Query.InternalTrees.Node joinNode) { System.Data.Entity.Core.Query.InternalTrees.Node n; if (this.NeedsJoinGraph(joinNode)) { n = this.ProcessJoinGraph(joinNode); if (n != joinNode) { this.m_treeModified = true; } } else { n = joinNode; } return(this.VisitDefaultForAllNodes(n)); }
private static bool ProcessGroupByOpWithNoAggregates( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node n, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { Command command = context.Command; GroupByOp op = (GroupByOp)n.Op; ExtendedNodeInfo extendedNodeInfo = command.GetExtendedNodeInfo(n.Child0); ProjectOp projectOp = command.CreateProjectOp(op.Keys); VarDefListOp varDefListOp = command.CreateVarDefListOp(); command.CreateNode((Op)varDefListOp); newNode = command.CreateNode((Op)projectOp, n.Child0, n.Child1); if (extendedNodeInfo.Keys.NoKeys || !op.Keys.Subsumes(extendedNodeInfo.Keys.KeyVars)) { newNode = command.CreateNode((Op)command.CreateDistinctOp(command.CreateVarVec(op.Keys)), newNode); } return(true); }
private static bool ProcessCrossApplyOverProject( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node applyNode, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { newNode = applyNode; System.Data.Entity.Core.Query.InternalTrees.Node child1 = applyNode.Child1; ProjectOp op = (ProjectOp)child1.Op; Command command = context.Command; ExtendedNodeInfo extendedNodeInfo = command.GetExtendedNodeInfo(applyNode); VarVec varVec = command.CreateVarVec(op.Outputs); varVec.Or(extendedNodeInfo.Definitions); op.Outputs.InitFrom(varVec); applyNode.Child1 = child1.Child0; context.Command.RecomputeNodeInfo(applyNode); child1.Child0 = applyNode; newNode = child1; return(true); }
protected override void VisitChildren(System.Data.Entity.Core.Query.InternalTrees.Node n) { bool flag = false; for (int index = 0; index < n.Children.Count; ++index) { System.Data.Entity.Core.Query.InternalTrees.Node child = n.Children[index]; n.Children[index] = this.VisitNode(n.Children[index]); if (!object.ReferenceEquals((object)child, (object)n.Children[index]) || this.changedNodes.Contains(child)) { flag = true; } } if (!flag) { return; } this.m_command.RecomputeNodeInfo(n); this.changedNodes.Add(n); }
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)); }
private static bool ProcessApplyOverAnything( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node applyNode, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { newNode = applyNode; System.Data.Entity.Core.Query.InternalTrees.Node child0 = applyNode.Child0; System.Data.Entity.Core.Query.InternalTrees.Node child1 = applyNode.Child1; ApplyBaseOp applyBaseOp = (ApplyBaseOp)applyNode.Op; Command command = context.Command; ExtendedNodeInfo extendedNodeInfo1 = command.GetExtendedNodeInfo(child1); ExtendedNodeInfo extendedNodeInfo2 = command.GetExtendedNodeInfo(child0); bool flag = false; if (applyBaseOp.OpType == OpType.OuterApply && extendedNodeInfo1.MinRows >= RowCount.One) { applyBaseOp = (ApplyBaseOp)command.CreateCrossApplyOp(); flag = true; } if (extendedNodeInfo1.ExternalReferences.Overlaps(extendedNodeInfo2.Definitions)) { if (!flag) { return(false); } newNode = command.CreateNode((Op)applyBaseOp, child0, child1); return(true); } if (applyBaseOp.OpType == OpType.CrossApply) { newNode = command.CreateNode((Op)command.CreateCrossJoinOp(), child0, child1); } else { LeftOuterJoinOp leftOuterJoinOp = command.CreateLeftOuterJoinOp(); ConstantPredicateOp trueOp = command.CreateTrueOp(); System.Data.Entity.Core.Query.InternalTrees.Node node = command.CreateNode((Op)trueOp); newNode = command.CreateNode((Op)leftOuterJoinOp, child0, child1, node); } return(true); }
private static bool ProcessLikeOverConstant( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node n, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { newNode = n; InternalConstantOp op1 = (InternalConstantOp)n.Child1.Op; InternalConstantOp op2 = (InternalConstantOp)n.Child0.Op; string str1 = (string)op2.Value; string str2 = (string)op1.Value; bool?nullable = ScalarOpRules.MatchesPattern((string)op2.Value, (string)op1.Value); if (!nullable.HasValue) { return(false); } ConstantPredicateOp constantPredicateOp = context.Command.CreateConstantPredicateOp(nullable.Value); newNode = context.Command.CreateNode((Op)constantPredicateOp); return(true); }
private static bool HasVarReferencesShallow( System.Data.Entity.Core.Query.InternalTrees.Node node, VarVec vars, int childIndex, out bool continueUp) { switch (node.Op.OpType) { case OpType.Project: continueUp = false; return(VarRefManager.HasVarReferences(((ProjectOp)node.Op).Outputs, vars)); case OpType.Sort: case OpType.ConstrainedSort: continueUp = true; return(VarRefManager.HasVarReferences(((SortBaseOp)node.Op).Keys, vars)); case OpType.GroupBy: continueUp = false; return(VarRefManager.HasVarReferences(((GroupByBaseOp)node.Op).Keys, vars)); case OpType.UnionAll: case OpType.Intersect: case OpType.Except: continueUp = false; return(VarRefManager.HasVarReferences((SetOp)node.Op, vars, childIndex)); case OpType.Distinct: continueUp = false; return(VarRefManager.HasVarReferences(((DistinctOp)node.Op).Keys, vars)); case OpType.PhysicalProject: continueUp = false; return(VarRefManager.HasVarReferences(((PhysicalProjectOp)node.Op).Outputs, vars)); default: continueUp = true; return(false); } }
internal System.Data.Entity.Core.Query.InternalTrees.Node GetInternalTree( Command targetIqtCommand, IList <System.Data.Entity.Core.Query.InternalTrees.Node> targetIqtArguments) { if (this.m_internalTreeNode == null) { DiscriminatorMap discriminatorMap; Command command = ITreeGenerator.Generate(this.GenerateFunctionView(out discriminatorMap), discriminatorMap); System.Data.Entity.Core.Query.InternalTrees.Node root = command.Root; System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(root.Op.OpType == OpType.PhysicalProject, "Expected a physical projectOp at the root of the tree - found " + (object)root.Op.OpType); PhysicalProjectOp op = (PhysicalProjectOp)root.Op; System.Data.Entity.Core.Query.InternalTrees.Node child0 = root.Child0; command.DisableVarVecEnumCaching(); System.Data.Entity.Core.Query.InternalTrees.Node relOpNode = child0; Var computedVar = op.Outputs[0]; if (!Command.EqualTypes(op.ColumnMap.Type, this.FunctionImport.ReturnParameter.TypeUsage)) { TypeUsage typeUsage = ((CollectionType)this.FunctionImport.ReturnParameter.TypeUsage.EdmType).TypeUsage; System.Data.Entity.Core.Query.InternalTrees.Node node1 = command.CreateNode((Op)command.CreateVarRefOp(computedVar)); System.Data.Entity.Core.Query.InternalTrees.Node node2 = command.CreateNode((Op)command.CreateSoftCastOp(typeUsage), node1); System.Data.Entity.Core.Query.InternalTrees.Node varDefListNode = command.CreateVarDefListNode(node2, out computedVar); ProjectOp projectOp = command.CreateProjectOp(computedVar); relOpNode = command.CreateNode((Op)projectOp, relOpNode, varDefListNode); } this.m_internalTreeNode = command.BuildCollect(relOpNode, computedVar); } Dictionary <string, System.Data.Entity.Core.Query.InternalTrees.Node> viewArguments = new Dictionary <string, System.Data.Entity.Core.Query.InternalTrees.Node>(this.m_commandParameters.Length); for (int index = 0; index < this.m_commandParameters.Length; ++index) { DbParameterReferenceExpression commandParameter = this.m_commandParameters[index]; System.Data.Entity.Core.Query.InternalTrees.Node node = targetIqtArguments[index]; if (TypeSemantics.IsEnumerationType(node.Op.Type)) { node = targetIqtCommand.CreateNode((Op)targetIqtCommand.CreateSoftCastOp(TypeHelpers.CreateEnumUnderlyingTypeUsage(node.Op.Type)), node); } viewArguments.Add(commandParameter.ParameterName, node); } return(FunctionImportMappingComposable.FunctionViewOpCopier.Copy(targetIqtCommand, this.m_internalTreeNode, viewArguments)); }
public override void Visit(SoftCastOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { PropertyRefList propertyRefs = (PropertyRefList)null; if (TypeSemantics.IsReferenceType(op.Type)) { propertyRefs = PropertyRefList.All; } else if (TypeSemantics.IsNominalType(op.Type)) { propertyRefs = this.m_nodePropertyRefMap[n].Clone(); } else if (TypeSemantics.IsRowType(op.Type)) { propertyRefs = PropertyRefList.All; } if (propertyRefs != null) { this.AddPropertyRefs(n.Child0, propertyRefs); } this.VisitChildren(n); }
private static bool ProcessApplyOverFilter( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node applyNode, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { newNode = applyNode; if (((TransformationRulesContext)context).PlanCompiler.TransformationsDeferred) { return(false); } System.Data.Entity.Core.Query.InternalTrees.Node child1 = applyNode.Child1; Command command = context.Command; if (command.GetNodeInfo(child1.Child0).ExternalReferences.Overlaps(command.GetExtendedNodeInfo(applyNode.Child0).Definitions)) { return(false); } JoinBaseOp joinBaseOp = applyNode.Op.OpType != OpType.CrossApply ? (JoinBaseOp)command.CreateLeftOuterJoinOp() : (JoinBaseOp)command.CreateInnerJoinOp(); newNode = command.CreateNode((Op)joinBaseOp, applyNode.Child0, child1.Child0, child1.Child1); return(true); }
private static bool ProcessIsNullOverCase( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node isNullOpNode, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { System.Data.Entity.Core.Query.InternalTrees.Node child0_1 = isNullOpNode.Child0; if (child0_1.Children.Count != 3) { newNode = isNullOpNode; return(false); } System.Data.Entity.Core.Query.InternalTrees.Node child0_2 = child0_1.Child0; System.Data.Entity.Core.Query.InternalTrees.Node child1 = child0_1.Child1; System.Data.Entity.Core.Query.InternalTrees.Node child2 = child0_1.Child2; switch (child1.Op.OpType) { case OpType.Constant: case OpType.InternalConstant: case OpType.NullSentinel: if (child2.Op.OpType == OpType.Null) { newNode = context.Command.CreateNode((Op)context.Command.CreateConditionalOp(OpType.Not), child0_2); return(true); } break; case OpType.Null: switch (child2.Op.OpType) { case OpType.Constant: case OpType.InternalConstant: case OpType.NullSentinel: newNode = child0_2; return(true); } } newNode = isNullOpNode; return(false); }
private static bool ProcessIsNullOverAnything( RuleProcessingContext context, System.Data.Entity.Core.Query.InternalTrees.Node isNullNode, out System.Data.Entity.Core.Query.InternalTrees.Node newNode) { Command command = context.Command; switch (isNullNode.Child0.Op.OpType) { case OpType.Cast: newNode = command.CreateNode((Op)command.CreateConditionalOp(OpType.IsNull), isNullNode.Child0.Child0); break; case OpType.Function: EdmFunction function = ((FunctionOp)isNullNode.Child0.Op).Function; newNode = ScalarOpRules.PreservesNulls(function) ? command.CreateNode((Op)command.CreateConditionalOp(OpType.IsNull), isNullNode.Child0.Child0) : isNullNode; break; default: newNode = isNullNode; break; } switch (isNullNode.Child0.Op.OpType) { case OpType.Constant: case OpType.InternalConstant: case OpType.NullSentinel: return(ScalarOpRules.ProcessIsNullOverConstant(context, newNode, out newNode)); case OpType.Null: return(ScalarOpRules.ProcessIsNullOverNull(context, newNode, out newNode)); case OpType.VarRef: return(ScalarOpRules.ProcessIsNullOverVarRef(context, newNode, out newNode)); default: return(!object.ReferenceEquals((object)isNullNode, (object)newNode)); } }
public override void Visit(ComparisonOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { TypeUsage type = (n.Child0.Op as ScalarOp).Type; if (!TypeUtils.IsStructuredType(type)) { this.VisitChildren(n); } else if (TypeSemantics.IsRowType(type) || TypeSemantics.IsReferenceType(type)) { this.VisitDefault(n); } else { System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(TypeSemantics.IsEntityType(type), "unexpected childOpType?"); PropertyRefList identityProperties = PropertyPushdownHelper.GetIdentityProperties(TypeHelpers.GetEdmType <EntityType>(type)); foreach (System.Data.Entity.Core.Query.InternalTrees.Node child in n.Children) { this.AddPropertyRefs(child, identityProperties); } this.VisitChildren(n); } }
internal bool HasKeyReferences(VarVec keys, System.Data.Entity.Core.Query.InternalTrees.Node definingNode, System.Data.Entity.Core.Query.InternalTrees.Node targetJoinNode) { System.Data.Entity.Core.Query.InternalTrees.Node key = definingNode; System.Data.Entity.Core.Query.InternalTrees.Node node; for (bool continueUp = true; continueUp& this.m_nodeToParentMap.TryGetValue(key, out node); key = node) { if (node != targetJoinNode) { if (VarRefManager.HasVarReferencesShallow(node, keys, this.m_nodeToSiblingNumber[key], out continueUp)) { return(true); } for (int index = this.m_nodeToSiblingNumber[key] + 1; index < node.Children.Count; ++index) { if (node.Children[index].GetNodeInfo(this.m_command).ExternalReferences.Overlaps(keys)) { return(true); } } } } return(false); }
protected override System.Data.Entity.Core.Query.InternalTrees.Node VisitGroupByOp( GroupByBaseOp op, System.Data.Entity.Core.Query.InternalTrees.Node n) { for (int index = n.Children.Count - 1; index >= 2; --index) { n.Children[index] = this.VisitNode(n.Children[index]); } if (op.Keys.Count > 1) { this.RemoveRedundantConstantKeys(op.Keys, op.Outputs, n.Child1); } this.AddReference((IEnumerable <Var>)op.Keys); n.Children[1] = this.VisitNode(n.Children[1]); n.Children[0] = this.VisitNode(n.Children[0]); this.PruneVarSet(op.Outputs); if (op.Keys.Count == 0 && op.Outputs.Count == 0) { return(this.m_command.CreateNode((Op)this.m_command.CreateSingleRowTableOp())); } this.m_command.RecomputeNodeInfo(n); return(n); }
internal System.Data.Entity.Core.Query.InternalTrees.Node ReMap( System.Data.Entity.Core.Query.InternalTrees.Node node, Dictionary <Var, System.Data.Entity.Core.Query.InternalTrees.Node> varMap) { System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(node.Op.IsScalarOp, "Expected a scalarOp: Found " + Dump.AutoString.ToString(node.Op.OpType)); if (node.Op.OpType == OpType.VarRef) { VarRefOp op = node.Op as VarRefOp; System.Data.Entity.Core.Query.InternalTrees.Node node1 = (System.Data.Entity.Core.Query.InternalTrees.Node)null; if (!varMap.TryGetValue(op.Var, out node1)) { return(node); } node1 = this.Copy(node1); return(node1); } for (int index = 0; index < node.Children.Count; ++index) { node.Children[index] = this.ReMap(node.Children[index], varMap); } this.Command.RecomputeNodeInfo(node); return(node); }
protected override System.Data.Entity.Core.Query.InternalTrees.Node VisitDefault(System.Data.Entity.Core.Query.InternalTrees.Node n) { List <System.Data.Entity.Core.Query.InternalTrees.Node> args = new List <System.Data.Entity.Core.Query.InternalTrees.Node>(n.Children.Count); bool flag = false; for (int index = 0; index < n.Children.Count; ++index) { System.Data.Entity.Core.Query.InternalTrees.Node node = this.VisitNode(n.Children[index]); if (node == null) { return((System.Data.Entity.Core.Query.InternalTrees.Node)null); } if (!flag && !object.ReferenceEquals((object)n.Children[index], (object)node)) { flag = true; } args.Add(node); } if (!flag) { return(n); } return(this._command.CreateNode(n.Op, args)); }
private void FindPathsToLeastCommonAncestor( System.Data.Entity.Core.Query.InternalTrees.Node node1, System.Data.Entity.Core.Query.InternalTrees.Node node2, out IList <System.Data.Entity.Core.Query.InternalTrees.Node> ancestors1, out IList <System.Data.Entity.Core.Query.InternalTrees.Node> ancestors2) { ancestors1 = this.FindAncestors(node1); ancestors2 = this.FindAncestors(node2); int index1 = ancestors1.Count - 1; int index2; for (index2 = ancestors2.Count - 1; ancestors1[index1] == ancestors2[index2]; --index2) { --index1; } for (int index3 = ancestors1.Count - 1; index3 > index1; --index3) { ancestors1.RemoveAt(index3); } for (int index3 = ancestors2.Count - 1; index3 > index2; --index3) { ancestors2.RemoveAt(index3); } }
private bool IsKeyPredicate( System.Data.Entity.Core.Query.InternalTrees.Node left, System.Data.Entity.Core.Query.InternalTrees.Node right, VarVec keyVars, VarVec definitions, out Var keyVar) { keyVar = (Var)null; if (left.Op.OpType != OpType.VarRef) { return(false); } VarRefOp op = (VarRefOp)left.Op; keyVar = op.Var; if (!keyVars.IsSet(keyVar)) { return(false); } VarVec varVec = this.m_command.GetNodeInfo(right).ExternalReferences.Clone(); varVec.And(definitions); return(varVec.IsEmpty); }
internal void SuppressFilterPushdown(System.Data.Entity.Core.Query.InternalTrees.Node n) { this.m_suppressions[n] = n; }
internal bool IsFilterPushdownSuppressed(System.Data.Entity.Core.Query.InternalTrees.Node n) { return(this.m_suppressions.ContainsKey(n)); }
internal bool IsScalarOpTree(System.Data.Entity.Core.Query.InternalTrees.Node node) { int nonLeafNodeCount = 0; return(this.IsScalarOpTree(node, (Dictionary <Var, int>)null, ref nonLeafNodeCount)); }
internal override void PreProcess(System.Data.Entity.Core.Query.InternalTrees.Node n) { this.m_remapper.RemapNode(n); this.Command.RecomputeNodeInfo(n); }
internal void RemapSubtree(System.Data.Entity.Core.Query.InternalTrees.Node subTree) { this.m_remapper.RemapSubtree(subTree); }
internal override int GetHashCode(System.Data.Entity.Core.Query.InternalTrees.Node node) { return(this.Command.GetNodeInfo(node).HashValue); }