Exemple #1
0
        private Node VisitNestOp(Node n)
        {
            NestBaseOp         op    = n.Op as NestBaseOp;
            SingleStreamNestOp ssnOp = op as SingleStreamNestOp;

            Debug.Assert(op != null);

            // Visit the Node's children and map their Vars
            List <Node> newChildren = ProcessChildren(n);

            Var newDiscriminator = null;

            if (ssnOp != null)
            {
                newDiscriminator = GetMappedVar(ssnOp.Discriminator);
            }
            List <CollectionInfo> newCollectionInfoList = new List <CollectionInfo>();

            foreach (CollectionInfo ci in op.CollectionInfo)
            {
                ColumnMap newColumnMap = Copy(ci.ColumnMap);

                Var newCollectionVar = m_destCmd.CreateComputedVar(ci.CollectionVar.Type);
                SetMappedVar(ci.CollectionVar, newCollectionVar);

                VarList        newFlattendElementVars = Copy(ci.FlattenedElementVars);
                VarVec         newKeys           = Copy(ci.Keys);
                List <SortKey> newSortKeys       = Copy(ci.SortKeys);
                CollectionInfo newCollectionInfo = Command.CreateCollectionInfo(newCollectionVar, newColumnMap, newFlattendElementVars, newKeys, newSortKeys, ci.DiscriminatorValue);
                newCollectionInfoList.Add(newCollectionInfo);
            }

            VarVec newOutputs = Copy(op.Outputs);

            NestBaseOp     newOp             = null;
            List <SortKey> newPrefixSortKeys = Copy(op.PrefixSortKeys);

            if (ssnOp != null)
            {
                VarVec newKeys = Copy(ssnOp.Keys);
                // Copy the SortOp's SortKeys
                List <SortKey> 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));
        }
        /// <summary>
        /// Convert a SingleStreamNestOp into a massive UnionAllOp
        /// </summary>
        /// <param name="nestOp"></param>
        /// <param name="nestNode"></param>
        /// <param name="drivingNodeVars"></param>
        /// <param name="discriminatorVarList"></param>
        /// <param name="discriminatorVar"></param>
        /// <param name="varMapList"></param>
        /// <returns></returns>
        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>
        /// <param name="op"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        ///
        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;
        }
Exemple #6
0
        protected override void VisitNestOp(NestBaseOp op, Node n)
        {
            Dictionary <string, object> attrs = new Dictionary <string, object>();

            SingleStreamNestOp ssnOp = op as SingleStreamNestOp;

            if (null != ssnOp)
            {
                attrs.Add("Discriminator", (ssnOp.Discriminator == null) ? "<null>" : ssnOp.Discriminator.ToString());
            }

            StringBuilder 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 (CollectionInfo ci in op.CollectionInfo)
                {
                    Dictionary <string, object> 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);
            }
        }
Exemple #7
0
 protected override void VisitNestOp(NestBaseOp op, Node n)
 {
     throw EntityUtil.NotSupported();
 }
 protected override void VisitNestOp(NestBaseOp op, Node n)
 {
     throw new NotSupportedException();
 }
        /// <summary>
        /// MultiStreamNestOp/SingleStreamNestOp common processing.
        ///
        /// Pretty much just verifies that we didn't leave a NestOp behind.
        /// </summary>
        /// <param name="op"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        ///
        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 (Node chi in n.Children)
            {
                if (IsNestOpNode(chi))
                {
                    throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.NestOverNest);
                }
            }
            return 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);
 }