Code:
/ 4.0 / 4.0 / untmp / 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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ColorPalette.cs
- WebPartEditorOkVerb.cs
- InstanceLockTracking.cs
- BitmapEffectGeneralTransform.cs
- IndexedString.cs
- DelayedRegex.cs
- WorkflowInstanceQuery.cs
- IconBitmapDecoder.cs
- CompressedStack.cs
- ProviderIncompatibleException.cs
- XmlILIndex.cs
- TextChange.cs
- SafeFindHandle.cs
- TransactionChannelFactory.cs
- WorkerRequest.cs
- SHA1.cs
- SafeCryptHandles.cs
- SpecialFolderEnumConverter.cs
- SettingsPropertyCollection.cs
- RegisteredExpandoAttribute.cs
- HttpModuleActionCollection.cs
- ProvidePropertyAttribute.cs
- DispatcherHooks.cs
- WeakReferenceEnumerator.cs
- LogArchiveSnapshot.cs
- ButtonChrome.cs
- JavaScriptSerializer.cs
- SelectionEditingBehavior.cs
- Converter.cs
- EntityFunctions.cs
- ExpressionContext.cs
- IListConverters.cs
- Module.cs
- ListItemCollection.cs
- OdbcConnectionString.cs
- AssemblyHash.cs
- HeaderUtility.cs
- SelectionService.cs
- CodeArgumentReferenceExpression.cs
- XmlWhitespace.cs
- RolePrincipal.cs
- SoapProtocolImporter.cs
- CounterCreationData.cs
- WebBrowserPermission.cs
- ColorMap.cs
- MouseWheelEventArgs.cs
- GroupAggregateExpr.cs
- VideoDrawing.cs
- WebHttpSecurityElement.cs
- BuildProvider.cs
- OleDbConnectionPoolGroupProviderInfo.cs
- ResourcePermissionBase.cs
- CachedBitmap.cs
- Repeater.cs
- SmiMetaDataProperty.cs
- AQNBuilder.cs
- EventRoute.cs
- Common.cs
- Speller.cs
- GridViewCancelEditEventArgs.cs
- ModelPropertyDescriptor.cs
- ModelTreeEnumerator.cs
- EntityReference.cs
- DrawingBrush.cs
- ArgumentOutOfRangeException.cs
- GroupBoxRenderer.cs
- PbrsForward.cs
- SqlGenerator.cs
- StringConcat.cs
- DataControlButton.cs
- TypeConverterMarkupExtension.cs
- _ConnectOverlappedAsyncResult.cs
- ConstructorBuilder.cs
- InputBindingCollection.cs
- DocumentXPathNavigator.cs
- GridView.cs
- NamespaceCollection.cs
- BaseDataBoundControl.cs
- VectorCollectionConverter.cs
- SendingRequestEventArgs.cs
- HttpListenerElement.cs
- ResourcesGenerator.cs
- ContourSegment.cs
- CompilerGlobalScopeAttribute.cs
- MaterializeFromAtom.cs
- GridViewDeletedEventArgs.cs
- elementinformation.cs
- CoreSwitches.cs
- BitmapEffect.cs
- CryptoApi.cs
- TextShapeableCharacters.cs
- SqlOuterApplyReducer.cs
- ToolTipService.cs
- DataGridViewCellValueEventArgs.cs
- ObjectNotFoundException.cs
- ConnectionManagementSection.cs
- WebBrowsableAttribute.cs
- ProtectedConfiguration.cs
- ForEach.cs
- TableLayoutStyleCollection.cs