/// <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) { ExtendedNodeInfo nodeInfo = node.GetExtendedNodeInfo(m_command); if (nodeInfo.Keys.NoKeys) { VisitNode(node); } return nodeInfo.Keys; }
private Node ProjectOpCase1(Node projectNode) { #if DEBUG var input = Dump.ToXml(projectNode); #endif //DEBUG var op = (ProjectOp)projectNode.Op; // Check to see if any of the computed Vars are in fact NestOps, and // construct a collection column map for them. var collectionInfoList = new List<CollectionInfo>(); var newChildren = new List<Node>(); var collectionNodes = new List<Node>(); var externalReferences = Command.CreateVarVec(); var collectionReferences = Command.CreateVarVec(); var definedVars = new List<Node>(); var referencedVars = new List<Node>(); foreach (var chi in projectNode.Child1.Children) { var varDefOp = (VarDefOp)chi.Op; var definingExprNode = chi.Child0; if (OpType.Collect == definingExprNode.Op.OpType) { PlanCompiler.Assert(definingExprNode.HasChild0, "collect without input?"); PlanCompiler.Assert(OpType.PhysicalProject == definingExprNode.Child0.Op.OpType, "collect without physicalProject?"); var physicalProjectNode = definingExprNode.Child0; // Update collection var->defining node map; m_definingNodeMap.Add(varDefOp.Var, physicalProjectNode); ConvertToNestOpInput( physicalProjectNode, varDefOp.Var, collectionInfoList, collectionNodes, externalReferences, collectionReferences); } else if (OpType.VarRef == definingExprNode.Op.OpType) { var refVar = ((VarRefOp)definingExprNode.Op).Var; Node physicalProjectNode; if (m_definingNodeMap.TryGetValue(refVar, out physicalProjectNode)) { physicalProjectNode = CopyCollectionVarDefinition(physicalProjectNode); //SQLBUDT #602888: We need to track the copy too, in case we need to reuse it m_definingNodeMap.Add(varDefOp.Var, physicalProjectNode); ConvertToNestOpInput( physicalProjectNode, varDefOp.Var, collectionInfoList, collectionNodes, externalReferences, collectionReferences); } else { referencedVars.Add(chi); newChildren.Add(chi); } } else { definedVars.Add(chi); newChildren.Add(chi); } } // If we haven't identified a set of collection nodes, then we're done. if (0 == collectionNodes.Count) { return projectNode; } // OK, we found something. We have some heavy lifting to perform. // Then we need to build up a MultiStreamNestOp above the ProjectOp and the // new collection nodes to get what we really need. // pretend that the keys included everything from the new projectOp var outputVars = Command.CreateVarVec(op.Outputs); // First we need to modify this physicalProjectNode to leave out the collection // Vars that we've just seen. var newProjectVars = Command.CreateVarVec(op.Outputs); newProjectVars.Minus(collectionReferences); // If there are any external references from any of the collections, add // those to the projectOp explicitly. This must be ok because the projectOp // could not have had any left-correlation newProjectVars.Or(externalReferences); // Create the new projectOp, and hook it into this one. The new projectOp // no longer references the collections in it's children; of course we only // construct a new projectOp if it actually projects out some Vars. if (!newProjectVars.IsEmpty) { if (IsNestOpNode(projectNode.Child0)) { // If the input is a nest node, we need to figure out what to do with the // rest of the in the VarDefList; we can't just pitch them, but we also // really want to have the input be a nestop. // // What we do is essentially push any non-collection VarDef�s down under // the driving node of the MSN: // // Project[Z,Y,W](Msn(X,Y),VarDef(Z=blah),VarDef(W=Collect(etc)) ==> MSN(MSN(Project[Z](X,VarDef(Z=blah)),Y),W) // // An optimization, of course being to not push anything down when there // aren't any extra vars defined. if (definedVars.Count == 0 && referencedVars.Count == 0) { // We'll just pick the NestNode; we expect MergeNestedNestOps to merge // it into what we're about to generate later. projectNode = projectNode.Child0; EnsureReferencedVarsAreRemoved(referencedVars, outputVars); } else { var nestedNestOp = (NestBaseOp)projectNode.Child0.Op; // Build the new ProjectOp to be used as input to the new nestedNestOp; // it's input is the input to the current nestedNestOp and a new // VarDefList with only the vars that were defined on the top level // ProjectOp. var newNestedProjectNodeInputs = new List<Node>(); newNestedProjectNodeInputs.Add(projectNode.Child0.Child0); referencedVars.AddRange(definedVars); newNestedProjectNodeInputs.Add(Command.CreateNode(Command.CreateVarDefListOp(), referencedVars)); var newNestedProjectOutputs = Command.CreateVarVec(nestedNestOp.Outputs); // SQLBUDT #508722: We need to remove the collection vars, // these are not produced by the project foreach (var ci in nestedNestOp.CollectionInfo) { newNestedProjectOutputs.Clear(ci.CollectionVar); } foreach (var varDefNode in referencedVars) { newNestedProjectOutputs.Set(((VarDefOp)varDefNode.Op).Var); } var newNestedProjectNode = Command.CreateNode( Command.CreateProjectOp(newNestedProjectOutputs), newNestedProjectNodeInputs); // Now build the new nestedNestedNestOp, with the new nestedProjectOp // as it's input; we have to update the outputs of the NestOp to include // the vars we pushed down. var newNestedNestOutputs = Command.CreateVarVec(newNestedProjectOutputs); newNestedNestOutputs.Or(nestedNestOp.Outputs); var newNestedNestOp = Command.CreateMultiStreamNestOp( nestedNestOp.PrefixSortKeys, newNestedNestOutputs, nestedNestOp.CollectionInfo); var newNestedNestNodeInputs = new List<Node>(); newNestedNestNodeInputs.Add(newNestedProjectNode); for (var j = 1; j < projectNode.Child0.Children.Count; j++) { newNestedNestNodeInputs.Add(projectNode.Child0.Children[j]); } projectNode = Command.CreateNode(newNestedNestOp, newNestedNestNodeInputs); // We don't need to remove or remap referenced vars here because // we're including them on the node we create; they won't become // invalid. } } else { var newProjectOp = Command.CreateProjectOp(newProjectVars); projectNode.Child1 = Command.CreateNode(projectNode.Child1.Op, newChildren); projectNode.Op = newProjectOp; EnsureReferencedVarsAreRemapped(referencedVars); } } else { projectNode = projectNode.Child0; EnsureReferencedVarsAreRemoved(referencedVars, outputVars); } // We need to make sure that we project out any external references to the driving // node that the nested collections have, or we're going to end up with unresolvable // vars when we pull them up over the current driving node. Of course, we only // want the references that are actually ON the driving node. externalReferences.And(projectNode.GetExtendedNodeInfo(Command).Definitions); outputVars.Or(externalReferences); // There are currently no prefix sortkeys. The processing for a SortOp may later // introduce some prefix sortkeys, but there aren't any now. var nestOp = Command.CreateMultiStreamNestOp(new List<SortKey>(), outputVars, collectionInfoList); // Insert the current node at the head of the the list of collections collectionNodes.Insert(0, projectNode); var nestNode = Command.CreateNode(nestOp, collectionNodes); // Finally, recompute node info Command.RecomputeNodeInfo(projectNode); Command.RecomputeNodeInfo(nestNode); #if DEBUG var size = input.Length; // GC.KeepAlive makes FxCop Grumpy. var output = Dump.ToXml(nestNode); #endif //DEBUG return nestNode; }
/// <summary> /// Get extended node information for a RelOpNode /// </summary> /// <param name="n">the node</param> /// <returns>extended node info for this node</returns> internal ExtendedNodeInfo GetExtendedNodeInfo(Node n) { return n.GetExtendedNodeInfo(this); }