/// <summary> /// Computes a NodeInfo for a NestOp (SingleStream/MultiStream). /// Definitions = OutputVars /// LocalDefinitions = Collection Vars /// Keys = Keys of my child /// External References = any external references from the inputs /// RowCount=default /// </summary> /// <param name="op"> The NestOp </param> /// <param name="n"> corresponding Node </param> protected override NodeInfo VisitNestOp(NestBaseOp op, Node n) { var ssnOp = op as SingleStreamNestOp; var nodeInfo = InitExtendedNodeInfo(n); foreach (var ci in op.CollectionInfo) { nodeInfo.LocalDefinitions.Set(ci.CollectionVar); } nodeInfo.Definitions.InitFrom(op.Outputs); // get external references from each child foreach (var chi in n.Children) { nodeInfo.ExternalReferences.Or(GetExtendedNodeInfo(chi).ExternalReferences); } // eliminate things I may have defined already (left correlation) nodeInfo.ExternalReferences.Minus(nodeInfo.Definitions); // Keys are from the driving node only. if (ssnOp == null) { nodeInfo.Keys.InitFrom(GetExtendedNodeInfo(n.Child0).Keys); } else { nodeInfo.Keys.InitFrom(ssnOp.Keys); } return(nodeInfo); }
protected override NodeInfo VisitNestOp(NestBaseOp op, Node n) { SingleStreamNestOp singleStreamNestOp = op as SingleStreamNestOp; ExtendedNodeInfo extendedNodeInfo = this.InitExtendedNodeInfo(n); foreach (CollectionInfo collectionInfo in op.CollectionInfo) { extendedNodeInfo.LocalDefinitions.Set(collectionInfo.CollectionVar); } extendedNodeInfo.Definitions.InitFrom(op.Outputs); foreach (Node child in n.Children) { extendedNodeInfo.ExternalReferences.Or(this.GetExtendedNodeInfo(child).ExternalReferences); } extendedNodeInfo.ExternalReferences.Minus(extendedNodeInfo.Definitions); if (singleStreamNestOp == null) { extendedNodeInfo.Keys.InitFrom(this.GetExtendedNodeInfo(n.Child0).Keys); } else { extendedNodeInfo.Keys.InitFrom((IEnumerable <Var>)singleStreamNestOp.Keys); } return((NodeInfo)extendedNodeInfo); }
private Node VisitNestOp(Node n) { var op = n.Op as NestBaseOp; var ssnOp = op as SingleStreamNestOp; Debug.Assert(op != null); // Visit the Node's children and map their Vars var newChildren = ProcessChildren(n); Var newDiscriminator = null; if (ssnOp != null) { newDiscriminator = GetMappedVar(ssnOp.Discriminator); } var newCollectionInfoList = new List <CollectionInfo>(); foreach (var ci in op.CollectionInfo) { var newColumnMap = Copy(ci.ColumnMap); Var newCollectionVar = m_destCmd.CreateComputedVar(ci.CollectionVar.Type); SetMappedVar(ci.CollectionVar, newCollectionVar); var newFlattendElementVars = Copy(ci.FlattenedElementVars); var newKeys = Copy(ci.Keys); var newSortKeys = Copy(ci.SortKeys); var newCollectionInfo = Command.CreateCollectionInfo( newCollectionVar, newColumnMap, newFlattendElementVars, newKeys, newSortKeys, ci.DiscriminatorValue); newCollectionInfoList.Add(newCollectionInfo); } var newOutputs = Copy(op.Outputs); NestBaseOp newOp = null; var newPrefixSortKeys = Copy(op.PrefixSortKeys); if (ssnOp != null) { var newKeys = Copy(ssnOp.Keys); // Copy the SortOp's SortKeys var newPostfixSortKeys = Copy(ssnOp.PostfixSortKeys); newOp = m_destCmd.CreateSingleStreamNestOp( newKeys, newPrefixSortKeys, newPostfixSortKeys, newOutputs, newCollectionInfoList, newDiscriminator); } else { newOp = m_destCmd.CreateMultiStreamNestOp(newPrefixSortKeys, newOutputs, newCollectionInfoList); } return(m_destCmd.CreateNode(newOp, newChildren)); }
private Node VisitNestOp(Node n) { NestBaseOp op = n.Op as NestBaseOp; SingleStreamNestOp singleStreamNestOp = op as SingleStreamNestOp; List <Node> args = this.ProcessChildren(n); Var discriminatorVar = (Var)null; if (singleStreamNestOp != null) { discriminatorVar = this.GetMappedVar(singleStreamNestOp.Discriminator); } List <CollectionInfo> collectionInfoList = new List <CollectionInfo>(); foreach (CollectionInfo collectionInfo1 in op.CollectionInfo) { ColumnMap columnMap = this.Copy(collectionInfo1.ColumnMap); Var computedVar = (Var)this.m_destCmd.CreateComputedVar(collectionInfo1.CollectionVar.Type); this.SetMappedVar(collectionInfo1.CollectionVar, computedVar); VarList flattenedElementVars = this.Copy(collectionInfo1.FlattenedElementVars); VarVec keys = this.Copy(collectionInfo1.Keys); List <SortKey> sortKeys = this.Copy(collectionInfo1.SortKeys); CollectionInfo collectionInfo2 = Command.CreateCollectionInfo(computedVar, columnMap, flattenedElementVars, keys, sortKeys, collectionInfo1.DiscriminatorValue); collectionInfoList.Add(collectionInfo2); } VarVec outputVars = this.Copy(op.Outputs); List <SortKey> prefixSortKeys = this.Copy(op.PrefixSortKeys); NestBaseOp nestBaseOp; if (singleStreamNestOp != null) { VarVec keys = this.Copy(singleStreamNestOp.Keys); List <SortKey> postfixSortKeys = this.Copy(singleStreamNestOp.PostfixSortKeys); nestBaseOp = (NestBaseOp)this.m_destCmd.CreateSingleStreamNestOp(keys, prefixSortKeys, postfixSortKeys, outputVars, collectionInfoList, discriminatorVar); } else { nestBaseOp = (NestBaseOp)this.m_destCmd.CreateMultiStreamNestOp(prefixSortKeys, outputVars, collectionInfoList); } return(this.m_destCmd.CreateNode((Op)nestBaseOp, args)); }
// <summary> // Convert a SingleStreamNestOp into a massive UnionAllOp // </summary> private Node BuildUnionAllSubqueryForNestOp( NestBaseOp nestOp, Node nestNode, VarList drivingNodeVars, VarList discriminatorVarList, out Var discriminatorVar, out List<Dictionary<Var, Var>> varMapList) { var drivingNode = nestNode.Child0; // For each of the NESTED collections... Node unionAllNode = null; VarList unionAllOutputs = null; for (var i = 1; i < nestNode.Children.Count; i++) { // Ensure we only use the driving collection tree once, so other // transformations do not unintentionally change more than one path. // To prevent nodes in the tree from being used in multiple paths, // we copy the driving input on successive nodes. VarList newDrivingNodeVars; Node newDrivingNode; VarList newFlattenedElementVars; Op op; if (i > 1) { newDrivingNode = OpCopier.Copy(Command, drivingNode, drivingNodeVars, out newDrivingNodeVars); // // Bug 450245: If we copied the driver node, then references to driver node vars // from the collection subquery must be patched up // var varRemapper = new VarRemapper(Command); for (var j = 0; j < drivingNodeVars.Count; j++) { varRemapper.AddMapping(drivingNodeVars[j], newDrivingNodeVars[j]); } // Remap all references in the current subquery varRemapper.RemapSubtree(nestNode.Children[i]); // Bug 479183: Remap the flattened element vars newFlattenedElementVars = varRemapper.RemapVarList(nestOp.CollectionInfo[i - 1].FlattenedElementVars); // Create a cross apply for all but the first collection op = Command.CreateCrossApplyOp(); } else { newDrivingNode = drivingNode; newDrivingNodeVars = drivingNodeVars; newFlattenedElementVars = nestOp.CollectionInfo[i - 1].FlattenedElementVars; // Create an outer apply for the first collection, // that way we ensure at least one row for each row in the driver node. op = Command.CreateOuterApplyOp(); } // Create an outer apply with the driver node and the nested collection. var applyNode = Command.CreateNode(op, newDrivingNode, nestNode.Children[i]); // Now create a ProjectOp that augments the output from the OuterApplyOp // with nulls for each column from other collections // Build the VarDefList (the list of vars) for the Project, starting // with the collection discriminator var var varDefListChildren = new List<Node>(); var projectOutputs = Command.CreateVarList(); // Add the collection discriminator var to the output. projectOutputs.Add(discriminatorVarList[i]); // Add all columns from the driving node projectOutputs.AddRange(newDrivingNodeVars); // Add all the vars from all the nested collections; for (var j = 1; j < nestNode.Children.Count; j++) { var otherCollectionInfo = nestOp.CollectionInfo[j - 1]; // For the current nested collection, we just pick the var that's // coming from there and don't need have a new var defined, but for // the rest we construct null values. if (i == j) { projectOutputs.AddRange(newFlattenedElementVars); } else { foreach (var v in otherCollectionInfo.FlattenedElementVars) { var nullOp = Command.CreateNullOp(v.Type); var nullOpNode = Command.CreateNode(nullOp); Var nullOpVar; var nullOpVarDefNode = Command.CreateVarDefNode(nullOpNode, out nullOpVar); varDefListChildren.Add(nullOpVarDefNode); projectOutputs.Add(nullOpVar); } } } var varDefListNode = Command.CreateNode(Command.CreateVarDefListOp(), varDefListChildren); // Now, build up the projectOp var projectOutputsVarSet = Command.CreateVarVec(projectOutputs); var projectOp = Command.CreateProjectOp(projectOutputsVarSet); var projectNode = Command.CreateNode(projectOp, applyNode, varDefListNode); // finally, build the union all if (unionAllNode == null) { unionAllNode = projectNode; unionAllOutputs = projectOutputs; } else { var unionAllMap = new VarMap(); var projectMap = new VarMap(); for (var idx = 0; idx < unionAllOutputs.Count; idx++) { Var outputVar = Command.CreateSetOpVar(unionAllOutputs[idx].Type); unionAllMap.Add(outputVar, unionAllOutputs[idx]); projectMap.Add(outputVar, projectOutputs[idx]); } var unionAllOp = Command.CreateUnionAllOp(unionAllMap, projectMap); unionAllNode = Command.CreateNode(unionAllOp, unionAllNode, projectNode); // Get the output vars from the union-op. This must be in the same order // as the original list of Vars unionAllOutputs = GetUnionOutputs(unionAllOp, unionAllOutputs); } } // We're done building the node, but now we have to build a mapping from // the before-Vars to the after-Vars varMapList = new List<Dictionary<Var, Var>>(); IEnumerator<Var> outputVarsEnumerator = unionAllOutputs.GetEnumerator(); if (!outputVarsEnumerator.MoveNext()) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 4, null); // more columns from children than are on the unionAll? } // The discriminator var is always first discriminatorVar = outputVarsEnumerator.Current; // Build a map for each input for (var i = 0; i < nestNode.Children.Count; i++) { var varMap = new Dictionary<Var, Var>(); var varList = (i == 0) ? drivingNodeVars : nestOp.CollectionInfo[i - 1].FlattenedElementVars; foreach (var v in varList) { if (!outputVarsEnumerator.MoveNext()) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 5, null); // more columns from children than are on the unionAll? } varMap[v] = outputVarsEnumerator.Current; } varMapList.Add(varMap); } if (outputVarsEnumerator.MoveNext()) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 6, null); // at this point, we better be done with both lists... } return unionAllNode; }
// <summary> // "Normalize" each input to the NestOp. // We're now in the context of a MultiStreamNestOp, and we're trying to convert this // into a SingleStreamNestOp. // Normalization specifically refers to // - augmenting each input with a discriminator value (that describes the collection) // - removing the sort node at the root (and capturing this information as part of the sortkeys) // </summary> // <param name="nestOp"> the nestOp </param> // <param name="nestNode"> the nestOp subtree </param> // <param name="discriminatorVarList"> Discriminator Vars for each Collection input </param> // <param name="sortKeys"> SortKeys (postfix) for each Collection input </param> private void NormalizeNestOpInputs( NestBaseOp nestOp, Node nestNode, out VarList discriminatorVarList, out List<List<SortKey>> sortKeys) { discriminatorVarList = Command.CreateVarList(); // We insert a dummy var and value at poistion 0 for the deriving node, which // we should never reference; discriminatorVarList.Add(null); sortKeys = new List<List<SortKey>>(); sortKeys.Add(nestOp.PrefixSortKeys); for (var i = 1; i < nestNode.Children.Count; i++) { var inputNode = nestNode.Children[i]; // Since we're called from ConvertToSingleStreamNest, it is possible that we have a // SingleStreamNest here, because the input to the MultiStreamNest we're converting // may have been a MultiStreamNest that was converted to a SingleStreamNest. var ssnOp = inputNode.Op as SingleStreamNestOp; // If this collection is a SingleStreamNest, we pull up the key information // in it, and pullup the input; if (null != ssnOp) { // Note that the sortKeys argument is 1:1 with the nestOp inputs, that is // each input may have exactly one entry in the list, so we have to combine // all of the sort key components (Prefix+Keys+Discriminator+PostFix) into // one list. var mySortKeys = BuildSortKeyList(ssnOp); sortKeys.Add(mySortKeys); inputNode = inputNode.Child0; } else { // If the current collection has a SortNode specified, then pull that // out, and add the information to the list of postfix SortColumns var sortOp = inputNode.Op as SortOp; if (null != sortOp) { inputNode = inputNode.Child0; // bypass the sort node // Add the sort keys to the list of postfix sort keys sortKeys.Add(sortOp.Keys); } else { // No postfix sort keys for this case sortKeys.Add(new List<SortKey>()); } } // #447304: Ensure that any SortKey Vars will be projected from the input in addition to showing up in the postfix sort keys // by adding them to the FlattenedElementVars for this NestOp input's CollectionInfo. var flattenedElementVars = nestOp.CollectionInfo[i - 1].FlattenedElementVars; foreach (var sortKey in sortKeys[i]) { if (!flattenedElementVars.Contains(sortKey.Var)) { flattenedElementVars.Add(sortKey.Var); } } // Add a discriminator column to the collection-side - this must // happen before the outer-apply is added on; we need to use the value of // the discriminator to distinguish between null and empty collections Var discriminatorVar; var augmentedInput = AugmentNodeWithInternalIntegerConstant(inputNode, i, out discriminatorVar); nestNode.Children[i] = augmentedInput; discriminatorVarList.Add(discriminatorVar); } }
// <summary> // MultiStreamNestOp/SingleStreamNestOp common processing. // Pretty much just verifies that we didn't leave a NestOp behind. // </summary> protected override Node VisitNestOp(NestBaseOp op, Node n) { // First, visit my children VisitChildren(n); // If any of the children are a nestOp, then we have a // problem; it shouldn't have happened. foreach (var chi in n.Children) { if (IsNestOpNode(chi)) { throw new InvalidOperationException(Strings.ADP_InternalProviderError((int)EntityUtil.InternalErrorCode.NestOverNest)); } } return n; }
private NestBaseOp GetNestOpWithConsolidatedSortKeys(NestBaseOp inputNestOp, List<SortKey> sortKeys) { NestBaseOp result; // Include the sort keys as the prefix sort keys; // Note that we can't actually have a SSNest at this point in // the tree; they're only introduced once we've processed the // entire tree. if (inputNestOp.PrefixSortKeys.Count == 0) { foreach (var sk in sortKeys) { //SQLBUDT #507170 - We can't just add the sort keys, we need to copy them, // to avoid changes to one to affect the other inputNestOp.PrefixSortKeys.Add(Command.CreateSortKey(sk.Var, sk.AscendingSort, sk.Collation)); } result = inputNestOp; } else { var sortVars = Command.CreateVarVec(); // First add the sort keys from the SortBaseOp, then the NestOp keys var sortKeyList = ConsolidateSortKeys(sortKeys, inputNestOp.PrefixSortKeys); PlanCompiler.Assert(inputNestOp is MultiStreamNestOp, "Unexpected SingleStreamNestOp?"); // Finally, build a new NestOp with the keys... result = Command.CreateMultiStreamNestOp(sortKeyList, inputNestOp.Outputs, inputNestOp.CollectionInfo); } return result; }
protected override void VisitNestOp(NestBaseOp op, Node n) { var attrs = new Dictionary <string, object>(); var ssnOp = op as SingleStreamNestOp; if (null != ssnOp) { attrs.Add("Discriminator", (ssnOp.Discriminator == null) ? "<null>" : ssnOp.Discriminator.ToString()); } var sb = new StringBuilder(); string separator; if (null != ssnOp) { sb.Length = 0; separator = string.Empty; foreach (var v in ssnOp.Keys) { sb.Append(separator); sb.Append(v.Id); separator = ","; } if (0 != sb.Length) { attrs.Add("Keys", sb.ToString()); } } using (new AutoXml(this, op, attrs)) { using (new AutoXml(this, "outputs")) { foreach (var v in op.Outputs) { DumpVar(v); } } foreach (var ci in op.CollectionInfo) { var attrs2 = new Dictionary <string, object>(); attrs2.Add("CollectionVar", ci.CollectionVar); if (null != ci.DiscriminatorValue) { attrs2.Add("DiscriminatorValue", ci.DiscriminatorValue); } if (0 != ci.FlattenedElementVars.Count) { attrs2.Add("FlattenedElementVars", FormatVarList(sb, ci.FlattenedElementVars)); } if (0 != ci.Keys.Count) { attrs2.Add("Keys", ci.Keys); } if (0 != ci.SortKeys.Count) { attrs2.Add("SortKeys", FormatVarList(sb, ci.SortKeys)); } using (new AutoXml(this, "collection", attrs2)) { ci.ColumnMap.Accept(ColumnMapDumper.Instance, this); } } VisitChildren(n); } }
/// <summary> /// Common handling for all nestOps /// </summary> /// <param name="op"> nest op </param> /// <param name="n"> </param> protected virtual void VisitNestOp(NestBaseOp op, Node n) { VisitPhysicalOpDefault(op, n); }
protected override void VisitNestOp(NestBaseOp op, Node n) { Dictionary <string, object> attrs1 = new Dictionary <string, object>(); SingleStreamNestOp singleStreamNestOp = op as SingleStreamNestOp; if (singleStreamNestOp != null) { attrs1.Add("Discriminator", singleStreamNestOp.Discriminator == null ? (object)"<null>" : (object)singleStreamNestOp.Discriminator.ToString()); } StringBuilder sb = new StringBuilder(); if (singleStreamNestOp != null) { sb.Length = 0; string str = string.Empty; foreach (Var key in singleStreamNestOp.Keys) { sb.Append(str); sb.Append(key.Id); str = ","; } if (sb.Length != 0) { attrs1.Add("Keys", (object)sb.ToString()); } } using (new Dump.AutoXml(this, (Op)op, attrs1)) { using (new Dump.AutoXml(this, "outputs")) { foreach (Var output in op.Outputs) { this.DumpVar(output); } } foreach (CollectionInfo collectionInfo in op.CollectionInfo) { Dictionary <string, object> attrs2 = new Dictionary <string, object>(); attrs2.Add("CollectionVar", (object)collectionInfo.CollectionVar); if (collectionInfo.DiscriminatorValue != null) { attrs2.Add("DiscriminatorValue", collectionInfo.DiscriminatorValue); } if (collectionInfo.FlattenedElementVars.Count != 0) { attrs2.Add("FlattenedElementVars", (object)Dump.FormatVarList(sb, collectionInfo.FlattenedElementVars)); } if (collectionInfo.Keys.Count != 0) { attrs2.Add("Keys", (object)collectionInfo.Keys); } if (collectionInfo.SortKeys.Count != 0) { attrs2.Add("SortKeys", (object)Dump.FormatVarList(sb, collectionInfo.SortKeys)); } using (new Dump.AutoXml(this, "collection", attrs2)) collectionInfo.ColumnMap.Accept <Dump>((ColumnMapVisitor <Dump>)Dump.ColumnMapDumper.Instance, this); } this.VisitChildren(n); } }
protected override void VisitNestOp(NestBaseOp op, Node n) { throw new NotSupportedException(); }
protected virtual void VisitNestOp(NestBaseOp op, Node n) { this.VisitPhysicalOpDefault((PhysicalOp)op, n); }
// <summary> // A default processor for all NestOps. // Allows new visitors to just override this to handle all NestOps // </summary> // <param name="op"> the NestOp </param> // <param name="n"> the node to process </param> // <returns> a potentially modified subtree </returns> protected virtual TResultType VisitNestOp(NestBaseOp op, Node n) { return(VisitPhysicalOpDefault(op, n)); }