Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Query / PlanCompiler / SubqueryTrackingVisitor.cs / 1305376 / SubqueryTrackingVisitor.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Data.Query.InternalTrees; //using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class... namespace System.Data.Query.PlanCompiler { ////// The SubqueryTracking Visitor serves as a base class for the visitors that may turn /// scalar subqueryies into outer-apply subqueries. /// internal abstract class SubqueryTrackingVisitor : BasicOpVisitorOfNode { #region Private State protected readonly PlanCompiler m_compilerState; protected Command m_command { get { return m_compilerState.Command; } } // nested subquery tracking protected readonly Stackm_ancestors = new Stack (); private readonly Dictionary > m_nodeSubqueries = new Dictionary >(); #endregion #region Constructor protected SubqueryTrackingVisitor(PlanCompiler planCompilerState) { this.m_compilerState = planCompilerState; } #endregion #region Subquery Handling /// /// Adds a subquery to the list of subqueries for the relOpNode /// /// the RelOp node /// the subquery protected void AddSubqueryToRelOpNode(Node relOpNode, Node subquery) { ListnestedSubqueries; // Create an entry in the map if there isn't one already if (!m_nodeSubqueries.TryGetValue(relOpNode, out nestedSubqueries)) { nestedSubqueries = new List (); m_nodeSubqueries[relOpNode] = nestedSubqueries; } // add this subquery to the list of currently tracked subqueries nestedSubqueries.Add(subquery); } /// /// Add a subquery to the "parent" relop node /// /// the output var to be used - at the current location - in lieu of the subquery /// the subquery to move ///a var ref node for the var returned from the subquery protected Node AddSubqueryToParentRelOp(Var outputVar, Node subquery) { Node ancestor = FindRelOpAncestor(); PlanCompiler.Assert(ancestor != null, "no ancestors found?"); AddSubqueryToRelOpNode(ancestor, subquery); subquery = m_command.CreateNode(m_command.CreateVarRefOp(outputVar)); return subquery; } ////// Find the first RelOp node that is in my ancestral path. /// If I see a PhysicalOp, then I don't have a RelOp parent /// ///the first RelOp node protected Node FindRelOpAncestor() { foreach (Node n in m_ancestors) { if (n.Op.IsRelOp) { return n; } else if (n.Op.IsPhysicalOp) { return null; } } return null; } #endregion #region Visitor Helpers ////// Extends the base class implementation of VisitChildren. /// Wraps the call to visitchildren() by first adding the current node /// to the stack of "ancestors", and then popping back the node at the end /// /// Current node protected override void VisitChildren(Node n) { // Push the current node onto the stack m_ancestors.Push(n); for (int i = 0; i < n.Children.Count; i++) { n.Children[i] = VisitNode(n.Children[i]); } m_ancestors.Pop(); } #endregion #region Visitor Methods #region RelOps ////// Augments a node with a number of OuterApply's - one for each subquery /// If S1, S2, ... are the list of subqueries for the node, and D is the /// original (driver) input, we convert D into /// OuterApply(OuterApply(D, S1), S2), ... /// /// the input (driver) node /// List of subqueries /// should the input node be first in the apply chain, or the last? ///The resulting node tree private Node AugmentWithSubqueries(Node input, Listsubqueries, bool inputFirst) { Node newNode; int subqueriesStartPos; if (inputFirst) { newNode = input; subqueriesStartPos = 0; } else { newNode = subqueries[0]; subqueriesStartPos = 1; } for (int i = subqueriesStartPos; i < subqueries.Count; i++) { OuterApplyOp op = m_command.CreateOuterApplyOp(); newNode = m_command.CreateNode(op, newNode, subqueries[i]); } if (!inputFirst) { // The driver node uses a cross apply to ensure that no results are produced // for an empty driver. newNode = m_command.CreateNode(m_command.CreateCrossApplyOp(), newNode, input); } // We may need to perform join elimination m_compilerState.MarkPhaseAsNeeded(PlanCompilerPhase.JoinElimination); return newNode; } /// /// Default processing for RelOps. /// - First, we mark the current node as its own ancestor (so that any /// subqueries that we detect internally will be added to this node's list) /// - then, visit each child /// - finally, accumulate all nested subqueries. /// - if the current RelOp has only one input, then add the nested subqueries via /// Outer apply nodes to this input. /// /// The interesting RelOps are /// Project, Filter, GroupBy, Sort, /// Should we break this out into separate functions instead? /// /// Current RelOp /// Node to process ///Current subtree protected override Node VisitRelOpDefault(RelOp op, Node n) { VisitChildren(n); // visit all my children first // Then identify all the subqueries that have shown up as part of my node // Create Apply Nodes for each of these. ListnestedSubqueries; if (m_nodeSubqueries.TryGetValue(n, out nestedSubqueries) && nestedSubqueries.Count > 0) { // Validate - this must only apply to the following nodes PlanCompiler.Assert( n.Op.OpType == OpType.Project || n.Op.OpType == OpType.Filter || n.Op.OpType == OpType.GroupBy || n.Op.OpType == OpType.GroupByInto, "VisitRelOpDefault: Unexpected op?" + n.Op.OpType); Node newInputNode = AugmentWithSubqueries(n.Child0, nestedSubqueries, true); // Now make this the new input child n.Child0 = newInputNode; } return n; } /// /// Processing for all JoinOps /// /// JoinOp /// Current subtree ///Whether the node was modified protected bool ProcessJoinOp(JoinBaseOp op, Node n) { VisitChildren(n); // visit all my children first // then check to see if we have any nested subqueries. This can only // occur in the join condition. // What we'll do in this case is to convert the join condition - "p" into // p -> Exists(Filter(SingleRowTableOp, p)) // We will then move the subqueries into an outerApply on the SingleRowTable ListnestedSubqueries; if (!m_nodeSubqueries.TryGetValue(n, out nestedSubqueries)) { return false; } PlanCompiler.Assert(n.Op.OpType == OpType.InnerJoin || n.Op.OpType == OpType.LeftOuterJoin || n.Op.OpType == OpType.FullOuterJoin, "unexpected op?"); PlanCompiler.Assert(n.HasChild2, "missing second child to JoinOp?"); Node joinCondition = n.Child2; Node inputNode = m_command.CreateNode(m_command.CreateSingleRowTableOp()); inputNode = AugmentWithSubqueries(inputNode, nestedSubqueries, true); Node filterNode = m_command.CreateNode(m_command.CreateFilterOp(), inputNode, joinCondition); Node existsNode = m_command.CreateNode(m_command.CreateExistsOp(), filterNode); n.Child2 = existsNode; return true; } /// /// Visitor for UnnestOp. If the child has any subqueries, we need to convert this /// into an /// OuterApply(S, Unnest) /// unlike the other cases where the OuterApply will appear as the input of the node /// /// the unnestOp /// current subtree ///modified subtree public override Node Visit(UnnestOp op, Node n) { VisitChildren(n); // visit all my children first ListnestedSubqueries; if (m_nodeSubqueries.TryGetValue(n, out nestedSubqueries)) { // We pass 'inputFirst = false' since the subqueries contribute to the driver in the unnest, // they are not generated by the unnest. Node newNode = AugmentWithSubqueries(n, nestedSubqueries, false /* inputFirst */); return newNode; } else { return n; } } #endregion #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Data.Query.InternalTrees; //using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class... namespace System.Data.Query.PlanCompiler { ////// The SubqueryTracking Visitor serves as a base class for the visitors that may turn /// scalar subqueryies into outer-apply subqueries. /// internal abstract class SubqueryTrackingVisitor : BasicOpVisitorOfNode { #region Private State protected readonly PlanCompiler m_compilerState; protected Command m_command { get { return m_compilerState.Command; } } // nested subquery tracking protected readonly Stackm_ancestors = new Stack (); private readonly Dictionary > m_nodeSubqueries = new Dictionary >(); #endregion #region Constructor protected SubqueryTrackingVisitor(PlanCompiler planCompilerState) { this.m_compilerState = planCompilerState; } #endregion #region Subquery Handling /// /// Adds a subquery to the list of subqueries for the relOpNode /// /// the RelOp node /// the subquery protected void AddSubqueryToRelOpNode(Node relOpNode, Node subquery) { ListnestedSubqueries; // Create an entry in the map if there isn't one already if (!m_nodeSubqueries.TryGetValue(relOpNode, out nestedSubqueries)) { nestedSubqueries = new List (); m_nodeSubqueries[relOpNode] = nestedSubqueries; } // add this subquery to the list of currently tracked subqueries nestedSubqueries.Add(subquery); } /// /// Add a subquery to the "parent" relop node /// /// the output var to be used - at the current location - in lieu of the subquery /// the subquery to move ///a var ref node for the var returned from the subquery protected Node AddSubqueryToParentRelOp(Var outputVar, Node subquery) { Node ancestor = FindRelOpAncestor(); PlanCompiler.Assert(ancestor != null, "no ancestors found?"); AddSubqueryToRelOpNode(ancestor, subquery); subquery = m_command.CreateNode(m_command.CreateVarRefOp(outputVar)); return subquery; } ////// Find the first RelOp node that is in my ancestral path. /// If I see a PhysicalOp, then I don't have a RelOp parent /// ///the first RelOp node protected Node FindRelOpAncestor() { foreach (Node n in m_ancestors) { if (n.Op.IsRelOp) { return n; } else if (n.Op.IsPhysicalOp) { return null; } } return null; } #endregion #region Visitor Helpers ////// Extends the base class implementation of VisitChildren. /// Wraps the call to visitchildren() by first adding the current node /// to the stack of "ancestors", and then popping back the node at the end /// /// Current node protected override void VisitChildren(Node n) { // Push the current node onto the stack m_ancestors.Push(n); for (int i = 0; i < n.Children.Count; i++) { n.Children[i] = VisitNode(n.Children[i]); } m_ancestors.Pop(); } #endregion #region Visitor Methods #region RelOps ////// Augments a node with a number of OuterApply's - one for each subquery /// If S1, S2, ... are the list of subqueries for the node, and D is the /// original (driver) input, we convert D into /// OuterApply(OuterApply(D, S1), S2), ... /// /// the input (driver) node /// List of subqueries /// should the input node be first in the apply chain, or the last? ///The resulting node tree private Node AugmentWithSubqueries(Node input, Listsubqueries, bool inputFirst) { Node newNode; int subqueriesStartPos; if (inputFirst) { newNode = input; subqueriesStartPos = 0; } else { newNode = subqueries[0]; subqueriesStartPos = 1; } for (int i = subqueriesStartPos; i < subqueries.Count; i++) { OuterApplyOp op = m_command.CreateOuterApplyOp(); newNode = m_command.CreateNode(op, newNode, subqueries[i]); } if (!inputFirst) { // The driver node uses a cross apply to ensure that no results are produced // for an empty driver. newNode = m_command.CreateNode(m_command.CreateCrossApplyOp(), newNode, input); } // We may need to perform join elimination m_compilerState.MarkPhaseAsNeeded(PlanCompilerPhase.JoinElimination); return newNode; } /// /// Default processing for RelOps. /// - First, we mark the current node as its own ancestor (so that any /// subqueries that we detect internally will be added to this node's list) /// - then, visit each child /// - finally, accumulate all nested subqueries. /// - if the current RelOp has only one input, then add the nested subqueries via /// Outer apply nodes to this input. /// /// The interesting RelOps are /// Project, Filter, GroupBy, Sort, /// Should we break this out into separate functions instead? /// /// Current RelOp /// Node to process ///Current subtree protected override Node VisitRelOpDefault(RelOp op, Node n) { VisitChildren(n); // visit all my children first // Then identify all the subqueries that have shown up as part of my node // Create Apply Nodes for each of these. ListnestedSubqueries; if (m_nodeSubqueries.TryGetValue(n, out nestedSubqueries) && nestedSubqueries.Count > 0) { // Validate - this must only apply to the following nodes PlanCompiler.Assert( n.Op.OpType == OpType.Project || n.Op.OpType == OpType.Filter || n.Op.OpType == OpType.GroupBy || n.Op.OpType == OpType.GroupByInto, "VisitRelOpDefault: Unexpected op?" + n.Op.OpType); Node newInputNode = AugmentWithSubqueries(n.Child0, nestedSubqueries, true); // Now make this the new input child n.Child0 = newInputNode; } return n; } /// /// Processing for all JoinOps /// /// JoinOp /// Current subtree ///Whether the node was modified protected bool ProcessJoinOp(JoinBaseOp op, Node n) { VisitChildren(n); // visit all my children first // then check to see if we have any nested subqueries. This can only // occur in the join condition. // What we'll do in this case is to convert the join condition - "p" into // p -> Exists(Filter(SingleRowTableOp, p)) // We will then move the subqueries into an outerApply on the SingleRowTable ListnestedSubqueries; if (!m_nodeSubqueries.TryGetValue(n, out nestedSubqueries)) { return false; } PlanCompiler.Assert(n.Op.OpType == OpType.InnerJoin || n.Op.OpType == OpType.LeftOuterJoin || n.Op.OpType == OpType.FullOuterJoin, "unexpected op?"); PlanCompiler.Assert(n.HasChild2, "missing second child to JoinOp?"); Node joinCondition = n.Child2; Node inputNode = m_command.CreateNode(m_command.CreateSingleRowTableOp()); inputNode = AugmentWithSubqueries(inputNode, nestedSubqueries, true); Node filterNode = m_command.CreateNode(m_command.CreateFilterOp(), inputNode, joinCondition); Node existsNode = m_command.CreateNode(m_command.CreateExistsOp(), filterNode); n.Child2 = existsNode; return true; } /// /// Visitor for UnnestOp. If the child has any subqueries, we need to convert this /// into an /// OuterApply(S, Unnest) /// unlike the other cases where the OuterApply will appear as the input of the node /// /// the unnestOp /// current subtree ///modified subtree public override Node Visit(UnnestOp op, Node n) { VisitChildren(n); // visit all my children first ListnestedSubqueries; if (m_nodeSubqueries.TryGetValue(n, out nestedSubqueries)) { // We pass 'inputFirst = false' since the subqueries contribute to the driver in the unnest, // they are not generated by the unnest. Node newNode = AugmentWithSubqueries(n, nestedSubqueries, false /* inputFirst */); return newNode; } else { return n; } } #endregion #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataGridViewCellValidatingEventArgs.cs
- SqlClientWrapperSmiStream.cs
- ReturnEventArgs.cs
- PerfCounterSection.cs
- DependencyPropertyChangedEventArgs.cs
- NameTable.cs
- WebPartZone.cs
- Convert.cs
- CredentialCache.cs
- FileLevelControlBuilderAttribute.cs
- GcSettings.cs
- IArgumentProvider.cs
- XamlTreeBuilder.cs
- RootBuilder.cs
- CheckedListBox.cs
- AsymmetricKeyExchangeFormatter.cs
- MessageSmuggler.cs
- externdll.cs
- SQLStringStorage.cs
- DataGridViewCellStyleChangedEventArgs.cs
- ListBoxChrome.cs
- ImageKeyConverter.cs
- XmlBoundElement.cs
- WebRequestModuleElement.cs
- EmptyEnumerator.cs
- ScriptComponentDescriptor.cs
- RelationshipEndCollection.cs
- XmlSiteMapProvider.cs
- XsdDateTime.cs
- GridEntry.cs
- JournalEntryStack.cs
- X509Certificate.cs
- RNGCryptoServiceProvider.cs
- OpCodes.cs
- OrderByQueryOptionExpression.cs
- PublishLicense.cs
- Message.cs
- RayMeshGeometry3DHitTestResult.cs
- isolationinterop.cs
- SimpleLine.cs
- SqlUserDefinedTypeAttribute.cs
- SafeSerializationManager.cs
- StatusBarItem.cs
- MasterPageCodeDomTreeGenerator.cs
- sapiproxy.cs
- XmlArrayItemAttribute.cs
- Menu.cs
- _ScatterGatherBuffers.cs
- XhtmlTextWriter.cs
- PrimaryKeyTypeConverter.cs
- Timer.cs
- ComponentEvent.cs
- Overlapped.cs
- CapabilitiesState.cs
- TabPanel.cs
- SimpleParser.cs
- EFColumnProvider.cs
- BigInt.cs
- SqlBulkCopyColumnMapping.cs
- HttpSessionStateBase.cs
- Compiler.cs
- PingReply.cs
- StringAnimationUsingKeyFrames.cs
- ObjectIDGenerator.cs
- DocumentGrid.cs
- PreProcessor.cs
- XmlCountingReader.cs
- DbDataReader.cs
- ScriptManager.cs
- Int16Converter.cs
- DBCommandBuilder.cs
- Object.cs
- String.cs
- ArrayMergeHelper.cs
- ColumnMapTranslator.cs
- DynamicField.cs
- RegistrySecurity.cs
- RelationshipManager.cs
- RoutingChannelExtension.cs
- SchemaMerger.cs
- Column.cs
- WorkflowInspectionServices.cs
- WebScriptClientGenerator.cs
- CompilerErrorCollection.cs
- LambdaSerializationException.cs
- TypeEnumerableViewSchema.cs
- DbUpdateCommandTree.cs
- InvalidProgramException.cs
- BitmapCodecInfoInternal.cs
- Operand.cs
- CodeAttachEventStatement.cs
- HandlerFactoryCache.cs
- StandardCommands.cs
- Size3D.cs
- XamlParser.cs
- _ListenerResponseStream.cs
- DbConnectionPoolCounters.cs
- WebBrowserProgressChangedEventHandler.cs
- SessionPageStateSection.cs
- ExclusiveCanonicalizationTransform.cs