1 //---------------------------------------------------------------------
2 // <copyright file="NodeInfo.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
11 using System.Collections.Generic;
12 using System.Globalization;
13 using System.Diagnostics;
14 using System.Data.Common;
15 using md=System.Data.Metadata.Edm;
17 namespace System.Data.Query.InternalTrees
20 /// The KeySet class encapsulates all information about the keys of a RelOp node in
22 /// A KeyVec is logically a set of vars that uniquely identify the row of the current
23 /// RelOp. Some RelOps may have no unique keys - such a state is identified by the
29 private VarVec m_keys;
30 private bool m_noKeys;
34 internal KeyVec(Command itree)
36 m_keys = itree.CreateVarVec();
41 internal void InitFrom(KeyVec keyset)
43 m_keys.InitFrom(keyset.m_keys);
44 m_noKeys = keyset.m_noKeys;
47 internal void InitFrom(IEnumerable<Var> varSet)
49 InitFrom(varSet, false);
52 internal void InitFrom(IEnumerable<Var> varSet, bool ignoreParameters)
54 m_keys.InitFrom(varSet, ignoreParameters);
55 // Bug 434541: An empty set of keys is not the same as "no" keys.
59 internal void InitFrom(KeyVec left, KeyVec right)
61 if (left.m_noKeys || right.m_noKeys)
68 m_keys.InitFrom(left.m_keys);
69 m_keys.Or(right.m_keys);
72 internal void InitFrom(List<KeyVec> keyVecList)
76 foreach (KeyVec keyVec in keyVecList)
83 m_keys.Or(keyVec.m_keys);
92 internal VarVec KeyVars { get { return m_keys; } }
93 internal bool NoKeys { get { return m_noKeys; } set { m_noKeys = value; } }
97 /// The NodeInfo class represents additional information about a node in the tree.
98 /// By default, this includes a set of external references for each node (ie) references
99 /// to Vars that are not defined in the same subtree
100 /// The NodeInfo class also includes a "hashValue" that is a hash value for the entire
101 /// subtree rooted at this node
102 /// NOTE: When adding a new member to track inforation, make sure to update the Clear method
103 /// in this class to set that member to the default value.
105 internal class NodeInfo
107 #region private state
108 private VarVec m_externalReferences;
109 protected int m_hashValue; // hash value for the node
113 internal NodeInfo(Command cmd)
115 m_externalReferences = cmd.CreateVarVec();
119 #region public methods
121 /// Clear out all information - usually used by a Recompute
123 internal virtual void Clear()
125 m_externalReferences.Clear();
130 /// All external references from this node
132 internal VarVec ExternalReferences
134 get { return m_externalReferences; }
138 /// Get the hash value for this nodeInfo
140 internal int HashValue
142 get { return m_hashValue; }
146 /// Compute the hash value for a Vec
148 /// <param name="vec"></param>
149 /// <returns></returns>
150 internal static int GetHashValue(VarVec vec)
153 foreach (Var v in vec)
155 hashValue ^= v.GetHashCode();
161 /// Computes the hash value for this node. The hash value is simply the
162 /// local hash value for this node info added with the hash values of the child
165 /// <param name="cmd">current command</param>
166 /// <param name="n">current node</param>
167 internal virtual void ComputeHashValue(Command cmd, Node n)
170 foreach (Node chi in n.Children)
172 NodeInfo chiNodeInfo = cmd.GetNodeInfo(chi);
173 m_hashValue ^= chiNodeInfo.HashValue;
176 m_hashValue = (m_hashValue << 4) ^ ((int)n.Op.OpType); // include the optype somehow
177 // Now compute my local hash value
178 m_hashValue = (m_hashValue << 4) ^ GetHashValue(m_externalReferences);
184 /// Enum describing row counts
186 internal enum RowCount : byte
199 /// Unbounded (unknown number of rows)
205 /// An ExtendedNodeInfo class adds additional information to a standard NodeInfo.
206 /// This class is usually applicable only to RelOps and PhysicalOps.
207 /// The ExtendedNodeInfo class has in addition to the information maintained by NodeInfo
209 /// - a set of local definitions
210 /// - a set of definitions
212 /// - a set of non-nullable definitions
213 /// - a set of non-nullable definitions that are visible at this node
214 /// NOTE: When adding a new member to track inforation, make sure to update the Clear method
215 /// in this class to set that member to the default value.
217 internal class ExtendedNodeInfo : NodeInfo
220 private VarVec m_localDefinitions;
221 private VarVec m_definitions;
222 private KeyVec m_keys;
223 private VarVec m_nonNullableDefinitions;
224 private VarVec m_nonNullableVisibleDefinitions;
225 private RowCount m_minRows;
226 private RowCount m_maxRows;
230 internal ExtendedNodeInfo(Command cmd)
233 m_localDefinitions = cmd.CreateVarVec();
234 m_definitions = cmd.CreateVarVec();
235 m_nonNullableDefinitions = cmd.CreateVarVec();
236 m_nonNullableVisibleDefinitions = cmd.CreateVarVec();
237 m_keys = new KeyVec(cmd);
238 m_minRows = RowCount.Zero;
239 m_maxRows = RowCount.Unbounded;
243 #region public methods
245 internal override void Clear()
248 m_definitions.Clear();
249 m_localDefinitions.Clear();
250 m_nonNullableDefinitions.Clear();
251 m_nonNullableVisibleDefinitions.Clear();
253 m_minRows = RowCount.Zero;
254 m_maxRows = RowCount.Unbounded;
258 /// Compute the hash value for this node
260 /// <param name="cmd"></param>
261 /// <param name="n"></param>
262 internal override void ComputeHashValue(Command cmd, Node n)
264 base.ComputeHashValue(cmd, n);
265 m_hashValue = (m_hashValue << 4) ^ NodeInfo.GetHashValue(this.Definitions);
266 m_hashValue = (m_hashValue << 4) ^ NodeInfo.GetHashValue(this.Keys.KeyVars);
271 /// Definitions made specifically by this node
273 internal VarVec LocalDefinitions { get { return m_localDefinitions; } }
275 /// All definitions visible as outputs of this node
277 internal VarVec Definitions { get { return m_definitions; } }
279 /// The keys for this node
281 internal KeyVec Keys { get { return m_keys; } }
283 /// The definitions of vars that are guaranteed to be non-nullable when output from this node
285 internal VarVec NonNullableDefinitions { get { return m_nonNullableDefinitions; } }
287 /// The definitions that come from the rel-op inputs of this node that are guaranteed to be non-nullable
289 internal VarVec NonNullableVisibleDefinitions { get { return m_nonNullableVisibleDefinitions; } }
291 /// Min number of rows returned from this node
293 internal RowCount MinRows
295 get { return m_minRows; }
296 set { m_minRows = value; ValidateRowCount(); }
299 /// Max rows returned from this node
301 internal RowCount MaxRows
303 get { return m_maxRows; }
304 set { m_maxRows = value; ValidateRowCount(); }
308 /// Set the rowcount for this node
310 /// <param name="minRows">min rows produced by this node</param>
311 /// <param name="maxRows">max rows produced by this node</param>
312 internal void SetRowCount(RowCount minRows, RowCount maxRows)
320 /// Initialize the rowcounts for this node from the source node
322 /// <param name="source">nodeinfo of source</param>
323 internal void InitRowCountFrom(ExtendedNodeInfo source)
325 m_minRows = source.m_minRows;
326 m_maxRows = source.m_maxRows;
331 #region private methods
332 private void ValidateRowCount()
334 Debug.Assert(m_maxRows >= m_minRows, "MaxRows less than MinRows?");
340 /// The NodeInfoVisitor is a simple class (ab)using the Visitor pattern to define
341 /// NodeInfo semantics for various nodes in the tree
343 internal class NodeInfoVisitor : BasicOpVisitorOfT<NodeInfo>
345 #region public methods
347 /// The only public method. Recomputes the nodeInfo for a node in the tree,
348 /// but only if the node info has already been computed.
349 /// Assumes that the NodeInfo for each child (if computed already) is valid
351 /// <param name="n">Node to get NodeInfo for</param>
352 internal void RecomputeNodeInfo(Node n)
354 if (n.IsNodeInfoInitialized)
356 NodeInfo nodeInfo = VisitNode(n);
357 nodeInfo.ComputeHashValue(this.m_command, n); // compute the hash value for this node
364 /// Basic constructor
366 /// <param name="command"></param>
367 internal NodeInfoVisitor(Command command)
373 #region private state
374 private Command m_command;
377 #region private methods
378 private NodeInfo GetNodeInfo(Node n)
380 return n.GetNodeInfo(m_command);
382 private ExtendedNodeInfo GetExtendedNodeInfo(Node n)
384 return n.GetExtendedNodeInfo(m_command);
386 private NodeInfo InitNodeInfo(Node n)
388 NodeInfo nodeInfo = GetNodeInfo(n);
392 private ExtendedNodeInfo InitExtendedNodeInfo(Node n)
394 ExtendedNodeInfo nodeInfo = GetExtendedNodeInfo(n);
400 #region VisitorHelpers
402 /// Default implementation for scalarOps. Simply adds up external references
405 /// <param name="n"></param>
406 /// <returns></returns>
407 protected override NodeInfo VisitDefault(Node n)
409 Debug.Assert(n.Op.IsScalarOp || n.Op.IsAncillaryOp, "not a supported optype");
411 NodeInfo nodeInfo = InitNodeInfo(n);
412 // My external references are simply the combination of external references
413 // of all my children
414 foreach (Node chi in n.Children)
416 NodeInfo childNodeInfo = GetNodeInfo(chi);
417 nodeInfo.ExternalReferences.Or(childNodeInfo.ExternalReferences);
423 /// The given definition is non nullable if it is a non-null constant
424 /// or a reference to non-nullable input
426 /// <param name="definition"></param>
427 /// <param name="nonNullableInputs"></param>
428 /// <returns></returns>
429 private bool IsDefinitionNonNullable(Node definition, VarVec nonNullableInputs)
431 return (definition.Op.OpType == OpType.Constant
432 || definition.Op.OpType == OpType.InternalConstant
433 || definition.Op.OpType == OpType.NullSentinel
434 || definition.Op.OpType == OpType.VarRef
435 && nonNullableInputs.IsSet(((VarRefOp)definition.Op).Var));
439 #region IOpVisitor<NodeInfo> Members
449 /// The only special case among all scalar and ancillaryOps. Simply adds
450 /// its var to the list of unreferenced Ops
452 /// <param name="op">The VarRefOp</param>
453 /// <param name="n">Current node</param>
454 /// <returns></returns>
455 public override NodeInfo Visit(VarRefOp op, Node n)
457 NodeInfo nodeInfo = InitNodeInfo(n);
458 nodeInfo.ExternalReferences.Set(op.Var);
465 protected override NodeInfo VisitRelOpDefault(RelOp op, Node n)
467 return Unimplemented(n);
471 /// Definitions = Local Definitions = referenced table columns
472 /// External References = none
473 /// Keys = keys of entity type
474 /// RowCount (default): MinRows = 0, MaxRows = *
475 /// NonNullableDefinitions : non nullable table columns that are definitions
476 /// NonNullableInputDefinitions : default(empty) because cannot be used
478 /// <param name="op">ScanTable/ScanView op</param>
479 /// <param name="n">current subtree</param>
480 /// <returns>nodeinfo for this subtree</returns>
481 protected override NodeInfo VisitTableOp(ScanTableBaseOp op, Node n)
483 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
484 // #479372 - only the "referenced" columns of the table should
485 // show up in the definitions
486 nodeInfo.LocalDefinitions.Or(op.Table.ReferencedColumns);
487 nodeInfo.Definitions.Or(op.Table.ReferencedColumns);
489 // get table's keys - but only if the key columns have been referenced
490 if (op.Table.ReferencedColumns.Subsumes(op.Table.Keys))
492 nodeInfo.Keys.InitFrom(op.Table.Keys);
494 // no external references
496 //non-nullable definitions
497 nodeInfo.NonNullableDefinitions.Or(op.Table.NonNullableColumns);
498 nodeInfo.NonNullableDefinitions.And(nodeInfo.Definitions);
504 /// Computes a NodeInfo for an UnnestOp.
505 /// Definitions = columns of the table produced by this Op
507 /// External References = the unnestVar + any external references of the
508 /// computed Var (if any)
509 /// RowCount (default): MinRows = 0; MaxRows = *
510 /// NonNullableDefinitions: default(empty)
511 /// NonNullableInputDefinitions : default(empty) because cannot be used
513 /// <param name="op"></param>
514 /// <param name="n"></param>
515 /// <returns></returns>
516 public override NodeInfo Visit(UnnestOp op, Node n)
518 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
519 foreach (Var v in op.Table.Columns)
521 nodeInfo.LocalDefinitions.Set(v);
522 nodeInfo.Definitions.Set(v);
525 // Process keys if it's a TVF with inferred keys, otherwise - no keys.
526 if (n.Child0.Op.OpType == OpType.VarDef && n.Child0.Child0.Op.OpType == OpType.Function && op.Table.Keys.Count > 0)
528 // This is a TVF case.
529 // Get table's keys - but only if they have been referenced.
530 if (op.Table.ReferencedColumns.Subsumes(op.Table.Keys))
532 nodeInfo.Keys.InitFrom(op.Table.Keys);
538 Debug.Assert(nodeInfo.Keys.NoKeys, "UnnestOp should have no keys in all cases except TVFs mapped to entities.");
541 // If I have a child, then my external references are my child's external references.
542 // Otherwise, my external reference is my unnestVar
545 NodeInfo childNodeInfo = GetNodeInfo(n.Child0);
546 nodeInfo.ExternalReferences.Or(childNodeInfo.ExternalReferences);
550 nodeInfo.ExternalReferences.Set(op.Var);
557 /// Walk through the computed vars defined by a VarDefListNode, and look for
558 /// "simple" Var renames. Build up a mapping from original Vars to the renamed Vars
560 /// <param name="varDefListNode">the varDefListNode subtree</param>
561 /// <returns>A dictionary of Var->Var renames</returns>
562 internal static Dictionary<Var, Var> ComputeVarRemappings(Node varDefListNode)
564 Debug.Assert(varDefListNode.Op.OpType == OpType.VarDefList);
566 Dictionary<Var, Var> varMap = new Dictionary<Var, Var>();
567 foreach (Node varDefNode in varDefListNode.Children)
569 VarRefOp varRefOp = varDefNode.Child0.Op as VarRefOp;
570 if (varRefOp != null)
572 VarDefOp varDefOp = varDefNode.Op as VarDefOp;
573 Debug.Assert(varDefOp != null);
574 varMap[varRefOp.Var] = varDefOp.Var;
581 /// Computes a NodeInfo for a ProjectOp.
582 /// Definitions = the Vars property of this Op
583 /// LocalDefinitions = list of computed Vars produced by this node
584 /// Keys = Keys of the input Relop (if they are all preserved)
585 /// External References = any external references from the computed Vars
586 /// RowCount = Input's RowCount
587 /// NonNullabeDefinitions = Outputs that are either among the NonNullableDefinitions of the child or
588 /// are constants defined on this node
589 /// NonNullableInputDefinitions = NonNullableDefinitions of the child
591 /// <param name="op">The ProjectOp</param>
592 /// <param name="n">corresponding Node</param>
593 /// <returns></returns>
594 public override NodeInfo Visit(ProjectOp op, Node n)
596 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
598 // Walk through my outputs and identify my "real" definitions
599 ExtendedNodeInfo relOpChildNodeInfo = GetExtendedNodeInfo(n.Child0);
600 // In the first pass, only definitions of the child are considered
601 // to be definitions - everything else is an external reference
602 foreach (Var v in op.Outputs)
604 if (relOpChildNodeInfo.Definitions.IsSet(v))
606 nodeInfo.Definitions.Set(v);
610 nodeInfo.ExternalReferences.Set(v);
614 //Nonnullable definitions
615 nodeInfo.NonNullableDefinitions.InitFrom(relOpChildNodeInfo.NonNullableDefinitions);
616 nodeInfo.NonNullableDefinitions.And(op.Outputs);
617 nodeInfo.NonNullableVisibleDefinitions.InitFrom(relOpChildNodeInfo.NonNullableDefinitions);
620 foreach (Node chi in n.Child1.Children)
622 VarDefOp varDefOp = chi.Op as VarDefOp;
623 NodeInfo chiNodeInfo = GetNodeInfo(chi.Child0);
624 nodeInfo.LocalDefinitions.Set(varDefOp.Var);
625 nodeInfo.ExternalReferences.Clear(varDefOp.Var);
626 nodeInfo.Definitions.Set(varDefOp.Var);
627 nodeInfo.ExternalReferences.Or(chiNodeInfo.ExternalReferences);
629 if (IsDefinitionNonNullable(chi.Child0, nodeInfo.NonNullableVisibleDefinitions))
631 nodeInfo.NonNullableDefinitions.Set(varDefOp.Var);
634 nodeInfo.ExternalReferences.Minus(relOpChildNodeInfo.Definitions);
635 nodeInfo.ExternalReferences.Or(relOpChildNodeInfo.ExternalReferences);
637 // Get the set of keys - simply the list of my child's keys, unless
638 // they're not all defined
639 nodeInfo.Keys.NoKeys = true;
640 if (!relOpChildNodeInfo.Keys.NoKeys)
642 // Check to see if any of my child's keys have been left by the wayside
643 // in that case, mark this node as having no keys
644 VarVec keyVec = m_command.CreateVarVec(relOpChildNodeInfo.Keys.KeyVars);
645 Dictionary<Var, Var> varRenameMap = ComputeVarRemappings(n.Child1);
646 VarVec mappedKeyVec = keyVec.Remap(varRenameMap);
647 VarVec mappedKeyVecClone = mappedKeyVec.Clone();
648 VarVec opVars = m_command.CreateVarVec(op.Outputs);
649 mappedKeyVec.Minus(opVars);
650 if (mappedKeyVec.IsEmpty)
652 nodeInfo.Keys.InitFrom(mappedKeyVecClone);
656 nodeInfo.InitRowCountFrom(relOpChildNodeInfo);
661 /// Computes a NodeInfo for a FilterOp.
662 /// Definitions = Definitions of the input Relop
663 /// LocalDefinitions = None
664 /// Keys = Keys of the input Relop
665 /// External References = any external references from the input + any external
666 /// references from the predicate
667 /// MaxOneRow = Input's RowCount
668 /// If the predicate is a "false" predicate, then max RowCount is zero
669 /// If we can infer additional info from the key-selector, we may be
670 /// able to get better estimates
671 /// NonNullabeDefinitions = NonNullabeDefinitions of the input RelOp
672 /// NonNullableInputDefinitions = NonNullabeDefinitions of the input RelOp
674 /// <param name="op">The FilterOp</param>
675 /// <param name="n">corresponding Node</param>
676 /// <returns></returns>
677 public override NodeInfo Visit(FilterOp op, Node n)
679 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
680 ExtendedNodeInfo relOpChildNodeInfo = GetExtendedNodeInfo(n.Child0);
681 NodeInfo predNodeInfo = GetNodeInfo(n.Child1);
683 // definitions are my child's definitions
684 nodeInfo.Definitions.Or(relOpChildNodeInfo.Definitions);
685 // No local definitions
687 // My external references are my child's external references + those made
689 nodeInfo.ExternalReferences.Or(relOpChildNodeInfo.ExternalReferences);
690 nodeInfo.ExternalReferences.Or(predNodeInfo.ExternalReferences);
691 nodeInfo.ExternalReferences.Minus(relOpChildNodeInfo.Definitions);
693 // my keys are my child's keys
694 nodeInfo.Keys.InitFrom(relOpChildNodeInfo.Keys);
696 //The non-nullable definitions are same as these of the child
697 nodeInfo.NonNullableDefinitions.InitFrom(relOpChildNodeInfo.NonNullableDefinitions);
698 nodeInfo.NonNullableVisibleDefinitions.InitFrom(relOpChildNodeInfo.NonNullableDefinitions);
700 // inherit max RowCount from child; set min RowCount to 0, because
701 // we require way more analysis to do anything smarter
702 nodeInfo.MinRows = RowCount.Zero;
703 // If the predicate is a "false" predicate, then we know that MaxRows
705 ConstantPredicateOp predicate = n.Child1.Op as ConstantPredicateOp;
706 if (predicate != null && predicate.IsFalse)
708 nodeInfo.MaxRows = RowCount.Zero;
712 nodeInfo.MaxRows = relOpChildNodeInfo.MaxRows;
718 /// Computes a NodeInfo for a GroupByOp.
719 /// Definitions = Keys + aggregates
720 /// LocalDefinitions = Keys + Aggregates
721 /// Keys = GroupBy Keys
722 /// External References = any external references from the input + any external
723 /// references from the local computed Vars
725 /// (1,1) if no group-by keys;
726 /// otherwise if input MinRows is 1 then (1, input MaxRows);
727 /// otherwise (0, input MaxRows)
728 /// NonNullableDefinitions: non-nullable keys
729 /// NonNullableInputDefinitions : default(empty)
731 /// <param name="op">The GroupByOp</param>
732 /// <param name="n">corresponding Node</param>
733 /// <returns></returns>
734 protected override NodeInfo VisitGroupByOp(GroupByBaseOp op, Node n)
736 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
737 ExtendedNodeInfo relOpChildNodeInfo = GetExtendedNodeInfo(n.Child0);
739 // all definitions are my outputs
740 nodeInfo.Definitions.InitFrom(op.Outputs);
741 nodeInfo.LocalDefinitions.InitFrom(nodeInfo.Definitions);
742 // my definitions are the keys and aggregates I define myself
744 // My references are my child's external references + those made
745 // by my keys and my aggregates
746 nodeInfo.ExternalReferences.Or(relOpChildNodeInfo.ExternalReferences);
747 foreach (Node chi in n.Child1.Children)
749 NodeInfo keyExprNodeInfo = GetNodeInfo(chi.Child0);
750 nodeInfo.ExternalReferences.Or(keyExprNodeInfo.ExternalReferences);
751 if (IsDefinitionNonNullable(chi.Child0, relOpChildNodeInfo.NonNullableDefinitions))
753 nodeInfo.NonNullableDefinitions.Set(((VarDefOp)chi.Op).Var);
757 // Non-nullable definitions: also all the keys that come from the input
758 nodeInfo.NonNullableDefinitions.Or(relOpChildNodeInfo.NonNullableDefinitions);
759 nodeInfo.NonNullableDefinitions.And(op.Keys);
761 //Handle all aggregates
762 for (int i = 2; i < n.Children.Count; i++)
764 foreach (Node chi in n.Children[i].Children)
766 NodeInfo aggExprNodeInfo = GetNodeInfo(chi.Child0);
767 nodeInfo.ExternalReferences.Or(aggExprNodeInfo.ExternalReferences);
771 // eliminate definitions of my input
772 nodeInfo.ExternalReferences.Minus(relOpChildNodeInfo.Definitions);
774 // my keys are my grouping keys
775 nodeInfo.Keys.InitFrom(op.Keys);
778 nodeInfo.MinRows = op.Keys.IsEmpty ? RowCount.One : (relOpChildNodeInfo.MinRows == RowCount.One ? RowCount.One : RowCount.Zero);
779 nodeInfo.MaxRows = op.Keys.IsEmpty ? RowCount.One : relOpChildNodeInfo.MaxRows;
785 /// Computes a NodeInfo for a CrossJoinOp.
786 /// Definitions = Definitions of my children
787 /// LocalDefinitions = None
788 /// Keys = Concatenation of the keys of my children (if every one of them has keys; otherwise, null)
789 /// External References = any external references from the inputs
790 /// RowCount: MinRows: min(min-rows of each child)
791 /// MaxRows: max(max-rows of each child)
792 /// NonNullableDefinitions : The NonNullableDefinitions of the children
793 /// NonNullableInputDefinitions : default(empty) because cannot be used
795 /// <param name="op">The CrossJoinOp</param>
796 /// <param name="n">corresponding Node</param>
797 /// <returns></returns>
798 public override NodeInfo Visit(CrossJoinOp op, Node n)
800 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
802 // No definitions of my own. Simply inherit from my children
803 // My external references are the union of my children's external
805 // And my keys are the concatenation of the keys of each of my
807 List<KeyVec> keyVecList = new List<KeyVec>();
808 RowCount maxCard = RowCount.Zero;
809 RowCount minCard = RowCount.One;
810 foreach (Node chi in n.Children)
812 ExtendedNodeInfo chiNodeInfo = GetExtendedNodeInfo(chi);
813 nodeInfo.Definitions.Or(chiNodeInfo.Definitions);
814 nodeInfo.ExternalReferences.Or(chiNodeInfo.ExternalReferences);
815 keyVecList.Add(chiNodeInfo.Keys);
817 nodeInfo.NonNullableDefinitions.Or(chiNodeInfo.NonNullableDefinitions);
819 // Not entirely precise, but good enough
820 if (chiNodeInfo.MaxRows > maxCard)
822 maxCard = chiNodeInfo.MaxRows;
824 if (chiNodeInfo.MinRows < minCard)
826 minCard = chiNodeInfo.MinRows;
829 nodeInfo.Keys.InitFrom(keyVecList);
831 nodeInfo.SetRowCount(minCard, maxCard);
837 /// Computes a NodeInfo for an Inner/LeftOuter/FullOuter JoinOp.
838 /// Definitions = Definitions of my children
839 /// LocalDefinitions = None
840 /// Keys = Concatenation of the keys of my children (if every one of them has keys; otherwise, null)
841 /// External References = any external references from the inputs + any external
842 /// references from the join predicates
844 /// FullOuterJoin: MinRows = 0, MaxRows = N
845 /// InnerJoin: MinRows = 0;
846 /// MaxRows = N; if both inputs have RowCount lesser than (or equal to) 1, then maxCard = 1
847 /// OuterJoin: MinRows = leftInput.MinRows
848 /// MaxRows = N; if both inputs have RowCount lesser than (or equal to) 1, then maxCard = 1
849 /// NonNullableDefinitions:
850 /// FullOuterJoin: None.
851 /// InnerJoin: NonNullableDefinitions of both children
852 /// LeftOuterJoin: NonNullableDefinitions of the left child
853 /// NonNullableInputDefinitions : NonNullabeDefinitions of both children
855 /// <param name="op">The JoinOp</param>
856 /// <param name="n">corresponding Node</param>
857 /// <returns></returns>
858 protected override NodeInfo VisitJoinOp(JoinBaseOp op, Node n)
860 if (!(op.OpType == OpType.InnerJoin ||
861 op.OpType == OpType.LeftOuterJoin ||
862 op.OpType == OpType.FullOuterJoin))
864 return Unimplemented(n);
867 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
869 // No definitions of my own. Simply inherit from my children
870 // My external references are the union of my children's external
872 // And my keys are the concatenation of the keys of each of my
874 ExtendedNodeInfo leftRelOpNodeInfo = GetExtendedNodeInfo(n.Child0);
875 ExtendedNodeInfo rightRelOpNodeInfo = GetExtendedNodeInfo(n.Child1);
876 NodeInfo predNodeInfo = GetNodeInfo(n.Child2);
878 nodeInfo.Definitions.Or(leftRelOpNodeInfo.Definitions);
879 nodeInfo.Definitions.Or(rightRelOpNodeInfo.Definitions);
881 nodeInfo.ExternalReferences.Or(leftRelOpNodeInfo.ExternalReferences);
882 nodeInfo.ExternalReferences.Or(rightRelOpNodeInfo.ExternalReferences);
883 nodeInfo.ExternalReferences.Or(predNodeInfo.ExternalReferences);
884 nodeInfo.ExternalReferences.Minus(nodeInfo.Definitions);
886 nodeInfo.Keys.InitFrom(leftRelOpNodeInfo.Keys, rightRelOpNodeInfo.Keys);
888 //Non-nullable definitions
889 if (op.OpType == OpType.InnerJoin || op.OpType == OpType.LeftOuterJoin)
891 nodeInfo.NonNullableDefinitions.InitFrom(leftRelOpNodeInfo.NonNullableDefinitions);
893 if (op.OpType == OpType.InnerJoin)
895 nodeInfo.NonNullableDefinitions.Or(rightRelOpNodeInfo.NonNullableDefinitions);
897 nodeInfo.NonNullableVisibleDefinitions.InitFrom(leftRelOpNodeInfo.NonNullableDefinitions);
898 nodeInfo.NonNullableVisibleDefinitions.Or(rightRelOpNodeInfo.NonNullableDefinitions);
902 if (op.OpType == OpType.FullOuterJoin)
904 minRows = RowCount.Zero;
905 maxRows = RowCount.Unbounded;
909 if ((leftRelOpNodeInfo.MaxRows > RowCount.One) ||
910 (rightRelOpNodeInfo.MaxRows > RowCount.One))
912 maxRows = RowCount.Unbounded;
916 maxRows = RowCount.One;
919 if (op.OpType == OpType.LeftOuterJoin)
921 minRows = leftRelOpNodeInfo.MinRows;
925 minRows = RowCount.Zero;
929 nodeInfo.SetRowCount(minRows, maxRows);
935 /// Computes a NodeInfo for a CrossApply/OuterApply op.
936 /// Definitions = Definitions of my children
937 /// LocalDefinitions = None
938 /// Keys = Concatenation of the keys of my children (if every one of them has keys; otherwise, null)
939 /// External References = any external references from the inputs
941 /// CrossApply: minRows=0; MaxRows=Unbounded
942 /// (MaxRows = 1, if both inputs have MaxRow less than or equal to 1)
943 /// OuterApply: minRows=leftInput.MinRows; MaxRows=Unbounded
944 /// (MaxRows = 1, if both inputs have MaxRow less than or equal to 1)
945 /// NonNullableDefinitions =
946 /// CrossApply: NonNullableDefinitions of both children
947 /// OuterApply: NonNullableDefinitions of the left child
948 /// NonNullableInputDefinitions = NonNullabeDefinitions of both children
950 /// <param name="op">The ApplyOp</param>
951 /// <param name="n">corresponding Node</param>
952 /// <returns></returns>
953 protected override NodeInfo VisitApplyOp(ApplyBaseOp op, Node n)
955 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
957 ExtendedNodeInfo leftRelOpNodeInfo = GetExtendedNodeInfo(n.Child0);
958 ExtendedNodeInfo rightRelOpNodeInfo = GetExtendedNodeInfo(n.Child1);
960 nodeInfo.Definitions.Or(leftRelOpNodeInfo.Definitions);
961 nodeInfo.Definitions.Or(rightRelOpNodeInfo.Definitions);
963 nodeInfo.ExternalReferences.Or(leftRelOpNodeInfo.ExternalReferences);
964 nodeInfo.ExternalReferences.Or(rightRelOpNodeInfo.ExternalReferences);
965 nodeInfo.ExternalReferences.Minus(nodeInfo.Definitions);
967 nodeInfo.Keys.InitFrom(leftRelOpNodeInfo.Keys, rightRelOpNodeInfo.Keys);
969 //NonNullableDefinitions
970 nodeInfo.NonNullableDefinitions.InitFrom(leftRelOpNodeInfo.NonNullableDefinitions);
971 if (op.OpType == OpType.CrossApply)
973 nodeInfo.NonNullableDefinitions.Or(rightRelOpNodeInfo.NonNullableDefinitions);
975 nodeInfo.NonNullableVisibleDefinitions.InitFrom(leftRelOpNodeInfo.NonNullableDefinitions);
976 nodeInfo.NonNullableVisibleDefinitions.Or(rightRelOpNodeInfo.NonNullableDefinitions);
979 if (leftRelOpNodeInfo.MaxRows <= RowCount.One &&
980 rightRelOpNodeInfo.MaxRows <= RowCount.One)
982 maxRows = RowCount.One;
986 maxRows = RowCount.Unbounded;
988 RowCount minRows = (op.OpType == OpType.CrossApply) ? RowCount.Zero : leftRelOpNodeInfo.MinRows;
989 nodeInfo.SetRowCount(minRows, maxRows);
995 /// Computes a NodeInfo for SetOps (UnionAll, Intersect, Except).
996 /// Definitions = OutputVars
997 /// LocalDefinitions = OutputVars
998 /// Keys = Output Vars for Intersect, Except. For UnionAll ??
999 /// External References = any external references from the inputs
1000 /// RowCount: Min = 0, Max = unbounded.
1001 /// For UnionAlls, MinRows = max(MinRows of left and right inputs)
1002 /// NonNullable definitions =
1003 /// UnionAll - Columns that are NonNullableDefinitions on both (children) sides
1004 /// Except - Columns that are NonNullableDefinitions on the left child side
1005 /// Intersect - Columns that are NonNullableDefinitions on either side
1006 /// NonNullableInputDefinitions = default(empty) because cannot be used
1008 /// <param name="op">The SetOp</param>
1009 /// <param name="n">corresponding Node</param>
1010 /// <returns></returns>
1011 protected override NodeInfo VisitSetOp(SetOp op, Node n)
1013 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
1015 // My definitions and my "all" definitions are simply my outputs
1016 nodeInfo.Definitions.InitFrom(op.Outputs);
1017 nodeInfo.LocalDefinitions.InitFrom(op.Outputs);
1019 ExtendedNodeInfo leftChildNodeInfo = GetExtendedNodeInfo(n.Child0);
1020 ExtendedNodeInfo rightChildNodeInfo = GetExtendedNodeInfo(n.Child1);
1022 RowCount minRows = RowCount.Zero;
1024 // My external references are the external references of both of
1026 nodeInfo.ExternalReferences.Or(leftChildNodeInfo.ExternalReferences);
1027 nodeInfo.ExternalReferences.Or(rightChildNodeInfo.ExternalReferences);
1029 if (op.OpType == OpType.UnionAll)
1031 minRows = (leftChildNodeInfo.MinRows > rightChildNodeInfo.MinRows) ? leftChildNodeInfo.MinRows : rightChildNodeInfo.MinRows;
1034 // for intersect, and exceptOps, the keys are simply the outputs.
1035 if (op.OpType == OpType.Intersect || op.OpType == OpType.Except)
1037 nodeInfo.Keys.InitFrom(op.Outputs);
1041 // UnionAlls are a lot more complicated. If we've gone through
1042 // keyPullup, we will have set some keys on it's input branches and
1043 // what we need to do here is get the keys from each branch and re-map
1044 // them to the output vars.
1046 // If the branchDiscriminator is not set on the unionAllOp, then
1047 // we haven't been through key pullup and we can't look at the keys
1048 // that the child nodes have, because they're not discriminated.
1050 // See the logic in KeyPullup, where we make sure that there are
1051 // actually branch discriminators on the input branches.
1052 UnionAllOp unionAllOp = (UnionAllOp)op;
1054 if (null == unionAllOp.BranchDiscriminator)
1056 nodeInfo.Keys.NoKeys = true;
1060 VarVec nodeKeys = m_command.CreateVarVec();
1061 VarVec mappedKeyVec;
1062 for (int i = 0; i < n.Children.Count; i++)
1064 ExtendedNodeInfo childNodeInfo = n.Children[i].GetExtendedNodeInfo(m_command);
1065 if (!childNodeInfo.Keys.NoKeys && !childNodeInfo.Keys.KeyVars.IsEmpty)
1067 mappedKeyVec = childNodeInfo.Keys.KeyVars.Remap(unionAllOp.VarMap[i].GetReverseMap());
1068 nodeKeys.Or(mappedKeyVec);
1072 // Each branch had better have keys, or we can't continue.
1078 // You might be tempted to ask: "Don't we need to add the branch discriminator
1079 // to the keys as well?" The reason we don't is that we wouldn't be here unless
1080 // we have a branch discriminator variable, which implies we've pulled up keys on
1081 // the inputs, and they'll already have the branch descriminator set in the keys
1082 // of each input, so we don't need to add that...
1083 if (nodeKeys.IsEmpty)
1085 nodeInfo.Keys.NoKeys = true;
1089 nodeInfo.Keys.InitFrom(nodeKeys);
1094 //Non-nullable definitions
1095 VarVec leftNonNullableVars = leftChildNodeInfo.NonNullableDefinitions.Remap(op.VarMap[0].GetReverseMap());
1096 nodeInfo.NonNullableDefinitions.InitFrom(leftNonNullableVars);
1098 if (op.OpType != OpType.Except)
1100 VarVec rightNonNullableVars = rightChildNodeInfo.NonNullableDefinitions.Remap(op.VarMap[1].GetReverseMap());
1101 if (op.OpType == OpType.Intersect)
1103 nodeInfo.NonNullableDefinitions.Or(rightNonNullableVars);
1107 nodeInfo.NonNullableDefinitions.And(rightNonNullableVars);
1111 nodeInfo.NonNullableDefinitions.And(op.Outputs);
1113 nodeInfo.MinRows = minRows;
1118 /// Computes a NodeInfo for a ConstrainedSortOp/SortOp.
1119 /// Definitions = Definitions of the input Relop
1120 /// LocalDefinitions = not allowed
1121 /// Keys = Keys of the input Relop
1122 /// External References = any external references from the input + any external
1123 /// references from the keys
1124 /// RowCount = Input's RowCount
1125 /// NonNullabeDefinitions = NonNullabeDefinitions of the input RelOp
1126 /// NonNullableInputDefinitions = NonNullabeDefinitions of the input RelOp
1128 /// <param name="op">The SortOp</param>
1129 /// <param name="n">corresponding Node</param>
1130 /// <returns></returns>
1131 protected override NodeInfo VisitSortOp(SortBaseOp op, Node n)
1133 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
1134 ExtendedNodeInfo relOpChildNodeInfo = GetExtendedNodeInfo(n.Child0);
1136 // definitions are my child's definitions
1137 nodeInfo.Definitions.Or(relOpChildNodeInfo.Definitions);
1139 // My references are my child's external references + those made
1141 nodeInfo.ExternalReferences.Or(relOpChildNodeInfo.ExternalReferences);
1142 nodeInfo.ExternalReferences.Minus(relOpChildNodeInfo.Definitions);
1144 // my keys are my child's keys
1145 nodeInfo.Keys.InitFrom(relOpChildNodeInfo.Keys);
1147 //Non-nullable definitions are same as the input
1148 nodeInfo.NonNullableDefinitions.InitFrom(relOpChildNodeInfo.NonNullableDefinitions);
1149 nodeInfo.NonNullableVisibleDefinitions.InitFrom(relOpChildNodeInfo.NonNullableDefinitions);
1151 //Row counts are same as the input
1152 nodeInfo.InitRowCountFrom(relOpChildNodeInfo);
1154 // For constrained sort, if the Limit value is Constant(1) and WithTies is false,
1155 // then MinRows and MaxRows can be adjusted to 0, 1.
1156 if (OpType.ConstrainedSort == op.OpType &&
1157 OpType.Constant == n.Child2.Op.OpType &&
1158 !((ConstrainedSortOp)op).WithTies)
1160 ConstantBaseOp constOp = (ConstantBaseOp)n.Child2.Op;
1161 if(TypeHelpers.IsIntegerConstant(constOp.Type, constOp.Value, 1))
1163 nodeInfo.SetRowCount(RowCount.Zero, RowCount.One);
1171 /// Computes a NodeInfo for Distinct.
1172 /// Definitions = OutputVars that are not external references
1173 /// LocalDefinitions = None
1174 /// Keys = Output Vars
1175 /// External References = any external references from the inputs
1176 /// RowCount = Input's RowCount
1177 /// NonNullabeDefinitions : NonNullabeDefinitions of the input RelOp that are outputs
1178 /// NonNullableInputDefinitions : default(empty) because cannot be used
1180 /// <param name="op">The DistinctOp</param>
1181 /// <param name="n">corresponding Node</param>
1182 /// <returns></returns>
1183 public override NodeInfo Visit(DistinctOp op, Node n)
1185 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
1187 //#497217 - The parameters should not be included as keys
1188 nodeInfo.Keys.InitFrom(op.Keys, true);
1190 // external references - inherit from child
1191 ExtendedNodeInfo childNodeInfo = GetExtendedNodeInfo(n.Child0);
1192 nodeInfo.ExternalReferences.InitFrom(childNodeInfo.ExternalReferences);
1194 // no local definitions - definitions are just the keys that are not external references
1195 foreach (Var v in op.Keys)
1197 if (childNodeInfo.Definitions.IsSet(v))
1199 nodeInfo.Definitions.Set(v);
1203 nodeInfo.ExternalReferences.Set(v);
1207 //Non-nullable definitions
1208 nodeInfo.NonNullableDefinitions.InitFrom(childNodeInfo.NonNullableDefinitions);
1209 nodeInfo.NonNullableDefinitions.And(op.Keys);
1211 nodeInfo.InitRowCountFrom(childNodeInfo);
1216 /// Compute NodeInfo for a SingleRowOp.
1217 /// Definitions = child's definitions
1218 /// Keys = child's keys
1219 /// Local Definitions = none
1220 /// External references = child's external references
1222 /// NonNullabeDefinitions = NonNullabeDefinitions of the input RelOp
1223 /// NonNullableInputDefinitions : default(empty) because cannot be used
1225 /// <param name="op">The SingleRowOp</param>
1226 /// <param name="n">current subtree</param>
1227 /// <returns>NodeInfo for this node</returns>
1228 public override NodeInfo Visit(SingleRowOp op, Node n)
1230 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
1231 ExtendedNodeInfo childNodeInfo = GetExtendedNodeInfo(n.Child0);
1232 nodeInfo.Definitions.InitFrom(childNodeInfo.Definitions);
1233 nodeInfo.Keys.InitFrom(childNodeInfo.Keys);
1234 nodeInfo.ExternalReferences.InitFrom(childNodeInfo.ExternalReferences);
1235 nodeInfo.NonNullableDefinitions.InitFrom(childNodeInfo.NonNullableDefinitions);
1236 nodeInfo.SetRowCount(RowCount.Zero, RowCount.One);
1241 /// SingleRowTableOp
1242 /// No definitions, external references, non-nullable definitions
1243 /// Keys = empty list (not the same as "no keys")
1244 /// RowCount = (1,1)
1246 /// <param name="op">the SingleRowTableOp</param>
1247 /// <param name="n">current subtree</param>
1248 /// <returns>nodeInfo for this subtree</returns>
1249 public override NodeInfo Visit(SingleRowTableOp op, Node n)
1251 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
1252 nodeInfo.Keys.NoKeys = false;
1253 nodeInfo.SetRowCount(RowCount.One, RowCount.One);
1261 /// Computes a NodeInfo for a PhysicalProjectOp.
1262 /// Definitions = OutputVars
1263 /// LocalDefinitions = None
1265 /// External References = any external references from the inputs
1266 /// RowCount=default
1267 /// NonNullabeDefinitions = NonNullabeDefinitions of the input RelOp that are among the definitions
1268 /// NonNullableInputDefinitions = NonNullabeDefinitions of the input RelOp
1270 /// <param name="op">The PhysicalProjectOp</param>
1271 /// <param name="n">corresponding Node</param>
1272 /// <returns></returns>
1273 public override NodeInfo Visit(PhysicalProjectOp op, Node n)
1275 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
1276 foreach (Node chi in n.Children)
1278 NodeInfo childNodeInfo = GetNodeInfo(chi);
1279 nodeInfo.ExternalReferences.Or(childNodeInfo.ExternalReferences);
1281 nodeInfo.Definitions.InitFrom(op.Outputs);
1282 nodeInfo.LocalDefinitions.InitFrom(nodeInfo.Definitions);
1285 // Inherit the keys from the child - but only if all the columns were projected
1288 ExtendedNodeInfo driverChildNodeInfo = GetExtendedNodeInfo(n.Child0);
1289 if (!driverChildNodeInfo.Keys.NoKeys)
1291 VarVec missingKeys = m_command.CreateVarVec(driverChildNodeInfo.Keys.KeyVars);
1292 missingKeys.Minus(nodeInfo.Definitions);
1293 if (missingKeys.IsEmpty)
1295 nodeInfo.Keys.InitFrom(driverChildNodeInfo.Keys);
1299 //Non-nullable definitions
1300 nodeInfo.NonNullableDefinitions.Or(driverChildNodeInfo.NonNullableDefinitions);
1301 nodeInfo.NonNullableDefinitions.And(nodeInfo.Definitions);
1302 nodeInfo.NonNullableVisibleDefinitions.Or(driverChildNodeInfo.NonNullableVisibleDefinitions);
1308 /// Computes a NodeInfo for a NestOp (SingleStream/MultiStream).
1309 /// Definitions = OutputVars
1310 /// LocalDefinitions = Collection Vars
1311 /// Keys = Keys of my child
1312 /// External References = any external references from the inputs
1313 /// RowCount=default
1315 /// <param name="op">The NestOp</param>
1316 /// <param name="n">corresponding Node</param>
1317 /// <returns></returns>
1318 protected override NodeInfo VisitNestOp(NestBaseOp op, Node n)
1320 SingleStreamNestOp ssnOp = op as SingleStreamNestOp;
1321 ExtendedNodeInfo nodeInfo = InitExtendedNodeInfo(n);
1323 foreach (CollectionInfo ci in op.CollectionInfo)
1325 nodeInfo.LocalDefinitions.Set(ci.CollectionVar);
1327 nodeInfo.Definitions.InitFrom(op.Outputs);
1329 // get external references from each child
1330 foreach (Node chi in n.Children)
1332 nodeInfo.ExternalReferences.Or(GetExtendedNodeInfo(chi).ExternalReferences);
1335 // eliminate things I may have defined already (left correlation)
1336 nodeInfo.ExternalReferences.Minus(nodeInfo.Definitions);
1338 // Keys are from the driving node only.
1341 nodeInfo.Keys.InitFrom(GetExtendedNodeInfo(n.Child0).Keys);
1345 nodeInfo.Keys.InitFrom(ssnOp.Keys);