示例#1
0
        public Node VarList()
        {
            var node = new VarList();

            node.Add(new Identifier()
            {
                AnchorToken = Expect(TokenCategory.IDENTIFIER)
            });
            while (CurrentToken == TokenCategory.COMMA)
            {
                Expect(TokenCategory.COMMA);
                node.Add(new Identifier()
                {
                    AnchorToken = Expect(TokenCategory.IDENTIFIER)
                });
            }
            return(node);
        }
示例#2
0
        public Node VarList()
        {
            var result = new VarList();

            result.Add(new Identifier()
            {
                AnchorToken = Expect(TokenCategory.IDENTIFIER)
            });

            while (CurrentToken == TokenCategory.LIST_ELEMENT)
            {
                Expect(TokenCategory.LIST_ELEMENT);
                result.Add(new Identifier()
                {
                    AnchorToken = Expect(TokenCategory.IDENTIFIER)
                });
            }

            return(result);
        }
示例#3
0
 // <summary>
 // Make a copy of the current node. Also return an ordered list of the new
 // Vars corresponding to the vars in "varList"
 // </summary>
 // <param name="cmd"> current command </param>
 // <param name="node"> the node to clone </param>
 // <param name="varList"> list of Vars </param>
 // <param name="newVarList"> list of "new" Vars </param>
 // <returns> the cloned node </returns>
 internal static Node Copy(Command cmd, Node node, VarList varList, out VarList newVarList)
 {
     VarMap varMap;
     var newNode = Copy(cmd, node, out varMap);
     newVarList = Command.CreateVarList();
     foreach (var v in varList)
     {
         var newVar = varMap[v];
         newVarList.Add(newVar);
     }
     return newNode;
 }
示例#4
0
        // <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);
            }
        }
示例#5
0
        // <summary>
        // convert MultiStreamNestOp to SingleStreamNestOp
        // </summary>
        // <remarks>
        // A MultiStreamNestOp is typically of the form M(D, N1, N2, ..., Nk)
        // where D is the driver stream, and N1, N2 etc. represent the collections.
        // In general, this can be converted into a SingleStreamNestOp over:
        // (D+ outerApply N1) AugmentedUnionAll (D+ outerApply N2) ...
        // Where:
        // D+ is D with an extra discriminator column that helps to identify
        // the specific collection.
        // AugmentedUnionAll is simply a unionAll where each branch of the
        // unionAll is augmented with nulls for the corresponding columns
        // of other tables in the branch
        // The simple case where there is only a single nested collection is easier
        // to address, and can be represented by:
        // MultiStreamNest(D, N1) => SingleStreamNest(OuterApply(D, N1))
        // The more complex case, where there is more than one nested column, requires
        // quite a bit more work:
        // MultiStreamNest(D, X, Y,...) => SingleStreamNest(UnionAll(Project{"1", D1...Dn, X1...Xn, nY1...nYn}(OuterApply(D, X)), Project{"2", D1...Dn, nX1...nXn, Y1...Yn}(OuterApply(D, Y)), ...))
        // Where:
        // D           is the driving collection
        // D1...Dn     are the columns from the driving collection
        // X           is the first nested collection
        // X1...Xn     are the columns from the first nested collection
        // nX1...nXn   are null values for all columns from the first nested collection
        // Y           is the second nested collection
        // Y1...Yn     are the columns from the second nested collection
        // nY1...nYn   are null values for all columns from the second nested collection
        // </remarks>
        private Node ConvertToSingleStreamNest(
            Node nestNode, Dictionary<Var, ColumnMap> varRefReplacementMap, VarList flattenedOutputVarList,
            out SimpleColumnMap[] parentKeyColumnMaps)
        {
#if DEBUG
            var input = Dump.ToXml(nestNode);
#endif
            //DEBUG
            var nestOp = (MultiStreamNestOp)nestNode.Op;

            // We can't convert this node to a SingleStreamNest until all it's MultiStreamNest 
            // inputs are converted, so do that first.
            for (var i = 1; i < nestNode.Children.Count; i++)
            {
                var chi = nestNode.Children[i];

                if (chi.Op.OpType
                    == OpType.MultiStreamNest)
                {
                    var chiCi = nestOp.CollectionInfo[i - 1];

                    var childFlattenedOutputVars = Command.CreateVarList();
                    SimpleColumnMap[] childKeyColumnMaps;

                    nestNode.Children[i] = ConvertToSingleStreamNest(
                        chi, varRefReplacementMap, childFlattenedOutputVars, out childKeyColumnMaps);

                    // Now this may seem odd here, and it may look like we should have done this
                    // inside the recursive ConvertToSingleStreamNest call above, but that call
                    // doesn't have access to the CollectionInfo for it's parent, which is what
                    // we need to manipulate before we enter the loop below where we try and fold
                    // THIS nestOp nodes into a singleStreamNestOp.
                    var childColumnMap = ColumnMapTranslator.Translate(chiCi.ColumnMap, varRefReplacementMap);

                    var childKeys = Command.CreateVarVec(((SingleStreamNestOp)nestNode.Children[i].Op).Keys);

                    nestOp.CollectionInfo[i - 1] = Command.CreateCollectionInfo(
                        chiCi.CollectionVar,
                        childColumnMap,
                        childFlattenedOutputVars,
                        childKeys,
                        chiCi.SortKeys,
                        null /*discriminatorValue*/
                        );
                }
            }

            // Make sure that the driving node has keys defined. Otherwise we're in
            // trouble; we must be able to infer keys from the driving node.
            var drivingNode = nestNode.Child0;
            var drivingNodeKeys = Command.PullupKeys(drivingNode);
            if (drivingNodeKeys.NoKeys)
            {
                // ALMINEEV: In this case we used to wrap drivingNode into a projection that would also project Edm.NewGuid() thus giving us a synthetic key.
                // This solution did not work however due to a bug in SQL Server that allowed pulling non-deterministic functions above joins and applies, thus 
                // producing incorrect results. SQL Server bug was filed in "sqlbuvsts01\Sql Server" database as #725272.
                // The only known path how we can get a keyless drivingNode is if 
                //    - drivingNode is over a TVF call
                //    - TVF is declared as Collection(Row) is SSDL (the only form of TVF definitions at the moment)
                //    - TVF is not mapped to entities
                //      Note that if TVF is mapped to entities via function import mapping, and the user query is actually the call of the 
                //      function import, we infer keys for the TVF from the c-space entity keys and their mappings.
                throw new NotSupportedException(Strings.ADP_KeysRequiredForNesting);
            }

            // Get a deterministic ordering of Vars from this node.
            // NOTE: we're using the drivingNode's definitions, which is a VarVec so it
            //       won't match the order of the input's columns, but the key thing is 
            //       that we use the same order for all nested children, so it's OK.
            var drivingNodeInfo = Command.GetExtendedNodeInfo(drivingNode);
            var drivingNodeVarVec = drivingNodeInfo.Definitions;
            var drivingNodeVars = Command.CreateVarList(drivingNodeVarVec);

            // Normalize all collection inputs to the nestOp. Specifically, remove any
            // SortOps (adding the sort keys to the postfix sortkey list). Additionally,
            // add a discriminatorVar to each collection child
            VarList discriminatorVarList;
            List<List<SortKey>> postfixSortKeyList;
            NormalizeNestOpInputs(nestOp, nestNode, out discriminatorVarList, out postfixSortKeyList);

            // Now build up the union-all subquery
            List<Dictionary<Var, Var>> varMapList;
            Var outputDiscriminatorVar;
            var unionAllNode = BuildUnionAllSubqueryForNestOp(
                nestOp, nestNode, drivingNodeVars, discriminatorVarList, out outputDiscriminatorVar, out varMapList);
            var drivingNodeVarMap = varMapList[0];

            // OK.  We've finally created the UnionAll over each of the project/outerApply
            // combinations.  We know that the output columns will be:
            //
            //      Discriminator, DrivingColumns, Collection1Columns, Collection2Columns, ...
            //
            // Now, rebuild the columnMaps, since all of the columns in the original column
            // maps are now referencing newer variables.  To do that, we'll walk the list of
            // outputs from the unionAll, and construct new VarRefColumnMaps for each one,
            // and adding it to a ColumnMapPatcher, which we'll use to actually fix everything
            // up.
            //
            // While we're at it, we'll build a new list of top-level output columns, which
            // should include only the Discriminator, the columns from the driving collection,
            // and and one column for each of the nested collections.

            // Start building the flattenedOutputVarList that the top level PhysicalProjectOp
            // is to output.
            flattenedOutputVarList.AddRange(RemapVars(drivingNodeVars, drivingNodeVarMap));

            var flattenedOutputVarVec = Command.CreateVarVec(flattenedOutputVarList);
            var nestOpOutputs = Command.CreateVarVec(flattenedOutputVarVec);

            // Add any adjustments to the driving nodes vars to the column map patcher
            foreach (var kv in drivingNodeVarMap)
            {
                if (kv.Key
                    != kv.Value)
                {
                    varRefReplacementMap[kv.Key] = new VarRefColumnMap(kv.Value);
                }
            }

            RemapSortKeys(nestOp.PrefixSortKeys, drivingNodeVarMap);

            var newPostfixSortKeys = new List<SortKey>();
            var newCollectionInfoList = new List<CollectionInfo>();

            // Build the discriminator column map, and ensure it's in the outputs
            var discriminatorColumnMap = new VarRefColumnMap(outputDiscriminatorVar);
            nestOpOutputs.Set(outputDiscriminatorVar);

            if (!flattenedOutputVarVec.IsSet(outputDiscriminatorVar))
            {
                flattenedOutputVarList.Add(outputDiscriminatorVar);
                flattenedOutputVarVec.Set(outputDiscriminatorVar);
            }

            // Build the key column maps, and ensure they're in the outputs as well.
            var parentKeys = RemapVarVec(drivingNodeKeys.KeyVars, drivingNodeVarMap);
            parentKeyColumnMaps = new SimpleColumnMap[parentKeys.Count];

            var index = 0;
            foreach (var keyVar in parentKeys)
            {
                parentKeyColumnMaps[index] = new VarRefColumnMap(keyVar);
                index++;

                if (!flattenedOutputVarVec.IsSet(keyVar))
                {
                    flattenedOutputVarList.Add(keyVar);
                    flattenedOutputVarVec.Set(keyVar);
                }
            }

            // Now that we've handled the driving node, deal with each of the 
            // nested inputs, in sequence.
            for (var i = 1; i < nestNode.Children.Count; i++)
            {
                var ci = nestOp.CollectionInfo[i - 1];
                var postfixSortKeys = postfixSortKeyList[i];

                RemapSortKeys(postfixSortKeys, varMapList[i]);
                newPostfixSortKeys.AddRange(postfixSortKeys);

                var newColumnMap = ColumnMapTranslator.Translate(ci.ColumnMap, varMapList[i]);
                var newFlattenedElementVars = RemapVarList(ci.FlattenedElementVars, varMapList[i]);
                var newCollectionKeys = RemapVarVec(ci.Keys, varMapList[i]);

                RemapSortKeys(ci.SortKeys, varMapList[i]);

                var newCollectionInfo = Command.CreateCollectionInfo(
                    ci.CollectionVar,
                    newColumnMap,
                    newFlattenedElementVars,
                    newCollectionKeys,
                    ci.SortKeys,
                    i);
                newCollectionInfoList.Add(newCollectionInfo);

                // For a collection Var, we add the flattened elementVars for the
                // collection in place of the collection Var itself, and we create
                // a new column map to represent all the stuff we've done.

                foreach (var v in newFlattenedElementVars)
                {
                    if (!flattenedOutputVarVec.IsSet(v))
                    {
                        flattenedOutputVarList.Add(v);
                        flattenedOutputVarVec.Set(v);
                    }
                }

                nestOpOutputs.Set(ci.CollectionVar);

                var keyColumnMapIndex = 0;
                var keyColumnMaps = new SimpleColumnMap[newCollectionInfo.Keys.Count];
                foreach (var keyVar in newCollectionInfo.Keys)
                {
                    keyColumnMaps[keyColumnMapIndex] = new VarRefColumnMap(keyVar);
                    keyColumnMapIndex++;
                }

                var collectionColumnMap = new DiscriminatedCollectionColumnMap(
                    TypeUtils.CreateCollectionType(newCollectionInfo.ColumnMap.Type),
                    newCollectionInfo.ColumnMap.Name,
                    newCollectionInfo.ColumnMap,
                    keyColumnMaps,
                    parentKeyColumnMaps,
                    discriminatorColumnMap,
                    newCollectionInfo.DiscriminatorValue
                    );
                varRefReplacementMap[ci.CollectionVar] = collectionColumnMap;
            }

            // Finally, build up the SingleStreamNest Node
            var newSsnOp = Command.CreateSingleStreamNestOp(
                parentKeys,
                nestOp.PrefixSortKeys,
                newPostfixSortKeys,
                nestOpOutputs,
                newCollectionInfoList,
                outputDiscriminatorVar);
            var newNestNode = Command.CreateNode(newSsnOp, unionAllNode);

#if DEBUG
            var size = input.Length; // GC.KeepAlive makes FxCop Grumpy.
            var output = Dump.ToXml(newNestNode);
#endif
            //DEBUG

            return newNestNode;
        }
示例#6
0
        /// <summary>
        /// Comments from Murali:
        ///
        ///   There are several cases to consider here.
        ///
        ///   Case 0:
        ///     Let’s assume that K1 is the set of keys ({k1, k2, ..., kn}) for the
        ///     first input, and K2 ({l1, l2, …}) is the set of keys for the second
        ///     input.
        ///
        ///     The best case is when both K1 and K2 have the same cardinality (hopefully
        ///     greater than 0), and the keys are in the same locations (ie) the corresponding
        ///     positions in the select-list.  Even in this case, its not enough to take
        ///     the keys, and treat them as the keys of the union-all. What we’ll need to
        ///     do is to add a “branch” discriminator constant for each branch of the
        ///     union-all, and use this as the prefix for the keys.
        ///
        ///     For example, if I had:
        ///
        ///         Select c1, c2, c3... from ...
        ///         Union all
        ///         Select d1, d2, d3... from ...
        ///
        ///     And for the sake of argument, lets say that {c2} and {d2} are the keys of
        ///     each of the branches. What you’ll need to do is to translate this into
        ///
        ///         Select 0 as bd, c1, c2, c3... from ...
        ///         Union all
        ///         Select 1 as bd, d1, d2, d3... from ...
        ///
        ///     And then treat {bd, c2/d2} as the key of the union-all
        ///
        ///   Case 1:  (actually, a subcase of Case 0):
        ///     Now, if the keys don’t align, then we can simply take the union of the
        ///     corresponding positions, and make them all the keys (we would still need
        ///     the branch discriminator)
        ///
        ///   Case 2:
        ///     Finally, if you need to “pull” up keys from either of the branches, it is
        ///     possible that the branches get out of whack.  We will then need to push up
        ///     the keys (with nulls if the other branch doesn’t have the corresponding key)
        ///     into the union-all. (We still need the branch discriminator).
        ///
        /// Now, unfortunately, whenever we've got polymorphic entity types, we'll end up
        /// in case 2 way more often than we really want to, because when we're pulling up
        /// keys, we don't want to reason about a caseop (which is how polymorphic types
        /// wrap their key value).
        ///
        /// To simplify all of this, we:
        ///
        /// (1) Pulling up the keys for both branches of the UnionAll, and computing which
        ///     keys are in the outputs and which are missing from the outputs.
        ///
        /// (2) Accumulate all the missing keys.
        ///
        /// (3) Slap a projectOp around each branch, adding a branch discriminator
        ///     var and all the missing keys.  When keys are missing from a different
        ///     branch, we'll construct null ops for them on the other branches.  If
        ///     a branch already has a branch descriminator, we'll re-use it instead
        ///     of constructing a new one.  (Of course, if there aren't any keys to
        ///     add and it's already including the branch discriminator we won't
        ///     need the projectOp)
        ///
        /// </summary>
        /// <param name="op">the UnionAllOp</param>
        /// <param name="n">current subtree</param>
        public override void Visit(UnionAllOp op, Node n)
        {
#if DEBUG
            string input = Dump.ToXml(m_command, n);
#endif //DEBUG

            // Ensure we have keys pulled up on each branch of the union all.
            VisitChildren(n);

            // Create the setOp var we'll use to output the branch discriminator value; if
            // any of the branches are already surfacing a branchDiscriminator var to the
            // output of this operation then we won't need to use this but we construct it
            // early to simplify logic.
            Var outputBranchDiscriminatorVar = m_command.CreateSetOpVar(m_command.IntegerType);

            // Now ensure that we're outputting the key vars from this op as well.
            VarList  allKeyVarsMissingFromOutput = Command.CreateVarList();
            VarVec[] keyVarsMissingFromOutput    = new VarVec[n.Children.Count];

            for (int i = 0; i < n.Children.Count; i++)
            {
                Node             branchNode     = n.Children[i];
                ExtendedNodeInfo branchNodeInfo = m_command.GetExtendedNodeInfo(branchNode);

                // Identify keys that aren't in the output list of this operation. We
                // determine these by remapping the keys that are found through the node's
                // VarMap, which gives us the keys in the same "varspace" as the outputs
                // of the UnionAll, then we subtract out the outputs of this UnionAll op,
                // leaving things that are not in the output vars.  Of course, if they're
                // not in the output vars, then we didn't really remap.
                VarVec existingKeyVars = branchNodeInfo.Keys.KeyVars.Remap(op.VarMap[i]);

                keyVarsMissingFromOutput[i] = m_command.CreateVarVec(existingKeyVars);
                keyVarsMissingFromOutput[i].Minus(op.Outputs);

                // Special Case: if the branch is a UnionAll, it will already have it's
                // branch discriminator var added in the keys; we don't want to add that
                // a second time...
                if (OpType.UnionAll == branchNode.Op.OpType)
                {
                    UnionAllOp branchUnionAllOp = (UnionAllOp)branchNode.Op;

                    keyVarsMissingFromOutput[i].Clear(branchUnionAllOp.BranchDiscriminator);
                }

                allKeyVarsMissingFromOutput.AddRange(keyVarsMissingFromOutput[i]);
            }

            // Construct the setOp vars we're going to map to output.
            VarList allKeyVarsToAddToOutput = Command.CreateVarList();

            foreach (Var v in allKeyVarsMissingFromOutput)
            {
                Var newKeyVar = m_command.CreateSetOpVar(v.Type);
                allKeyVarsToAddToOutput.Add(newKeyVar);
            }

            // Now that we've identified all the keys we need to add, ensure that each branch
            // has both the branch discrimination var and the all the keys in them, even when
            // the keys are just going to null (which we construct, as needed)
            for (int i = 0; i < n.Children.Count; i++)
            {
                Node             branchNode     = n.Children[i];
                ExtendedNodeInfo branchNodeInfo = m_command.GetExtendedNodeInfo(branchNode);

                VarVec      branchOutputVars = m_command.CreateVarVec();
                List <Node> varDefNodes      = new List <Node>();

                // If the branch is a UnionAllOp that has a branch discriminator var then we can
                // use it, otherwise we'll construct a new integer constant with the next value
                // of the branch discriminator value from the command object.
                Var branchDiscriminatorVar;

                if (OpType.UnionAll == branchNode.Op.OpType && null != ((UnionAllOp)branchNode.Op).BranchDiscriminator)
                {
                    branchDiscriminatorVar = ((UnionAllOp)branchNode.Op).BranchDiscriminator;

                    // If the branch has a discriminator var, but we haven't added it to the
                    // varmap yet, then we do so now.
                    if (!op.VarMap[i].ContainsValue(branchDiscriminatorVar))
                    {
                        op.VarMap[i].Add(outputBranchDiscriminatorVar, branchDiscriminatorVar);
                        // We don't need to add this to the branch outputs, because it's already there,
                        // otherwise we wouln't have gotten here, yes?
                    }
                    else
                    {
                        // In this case, we're already outputting the branch discriminator var -- we'll
                        // just use it for both sides.  We should never have a case where only one of the
                        // two branches are outputting the branch discriminator var, because it can only
                        // be constructed in this method, and we wouldn't need it for any other purpose.
                        PlanCompiler.Assert(0 == i, "right branch has a discriminator var that the left branch doesn't have?");
                        VarMap reverseVarMap = op.VarMap[i].GetReverseMap();
                        outputBranchDiscriminatorVar = reverseVarMap[branchDiscriminatorVar];
                    }
                }
                else
                {
                    // Not a unionAll -- we have to add a BranchDiscriminator var.
                    varDefNodes.Add(
                        m_command.CreateVarDefNode(
                            m_command.CreateNode(
                                m_command.CreateConstantOp(m_command.IntegerType, m_command.NextBranchDiscriminatorValue)), out branchDiscriminatorVar));

                    branchOutputVars.Set(branchDiscriminatorVar);
                    op.VarMap[i].Add(outputBranchDiscriminatorVar, branchDiscriminatorVar);
                }

                // Append all the missing keys to the branch outputs.  If the missing key
                // is not from this branch then create a null.
                for (int j = 0; j < allKeyVarsMissingFromOutput.Count; j++)
                {
                    Var keyVar = allKeyVarsMissingFromOutput[j];

                    if (!keyVarsMissingFromOutput[i].IsSet(keyVar))
                    {
                        varDefNodes.Add(
                            m_command.CreateVarDefNode(
                                m_command.CreateNode(
                                    m_command.CreateNullOp(keyVar.Type)), out keyVar));

                        branchOutputVars.Set(keyVar);
                    }

                    // In all cases, we're adding a key to the output so we need to update the
                    // varmap.
                    op.VarMap[i].Add(allKeyVarsToAddToOutput[j], keyVar);
                }

                // If we got this far and didn't add anything to the branch, then we're done.
                // Otherwise we'll have to construct the new projectOp around the input branch
                // to add the stuff we've added.
                if (branchOutputVars.IsEmpty)
                {
                    // Actually, we're not quite done -- we need to update the key vars for the
                    // branch to include the branch discriminator var we
                    branchNodeInfo.Keys.KeyVars.Set(branchDiscriminatorVar);
                }
                else
                {
                    PlanCompiler.Assert(varDefNodes.Count != 0, "no new nodes?");

                    // Start by ensuring all the existing outputs from the branch are in the list.
                    foreach (Var v in op.VarMap[i].Values)
                    {
                        branchOutputVars.Set(v);
                    }

                    // Now construct a project op to project out everything we've added, and
                    // replace the branchNode with it in the flattened ladder.
                    n.Children[i] = m_command.CreateNode(m_command.CreateProjectOp(branchOutputVars),
                                                         branchNode,
                                                         m_command.CreateNode(m_command.CreateVarDefListOp(), varDefNodes));

                    // Finally, ensure that we update the Key info for the projectOp to include
                    // the original branch's keys, along with the branch discriminator var.
                    m_command.RecomputeNodeInfo(n.Children[i]);
                    ExtendedNodeInfo projectNodeInfo = m_command.GetExtendedNodeInfo(n.Children[i]);
                    projectNodeInfo.Keys.KeyVars.InitFrom(branchNodeInfo.Keys.KeyVars);
                    projectNodeInfo.Keys.KeyVars.Set(branchDiscriminatorVar);
                }
            }

            // All done with the branches, now it's time to update the UnionAll op to indicate
            // that we've got a branch discriminator var.
            n.Op = m_command.CreateUnionAllOp(op.VarMap[0], op.VarMap[1], outputBranchDiscriminatorVar);

            // Finally, the thing we've all been waiting for -- computing the keys.  We cheat here and let
            // nodeInfo do it so we don't have to duplicate the logic...
            m_command.RecomputeNodeInfo(n);

#if DEBUG
            input = input.Trim();
            string output = Dump.ToXml(m_command, n);
#endif //DEBUG
        }
        //=========== LOADING ============
        #region Loading

        /**<summary>Loads the item modification from xml.</summary>*/
        public void LoadXml(XmlNode node)
        {
            List <string> unrecognized   = new List <string>();
            List <string> parsingErrors  = new List <string>();
            List <string> alreadyDefined = new List <string>();
            bool          looseText      = false;

            // Read all variables
            XmlNodeList nodeList = node.ChildNodes;

            foreach (XmlNode varNode in nodeList)
            {
                string varName = varNode.Name;
                if (varName == "#comment")
                {
                    continue;
                }
                else if (varName == "#text")
                {
                    looseText = true;
                }
                try {
                    if (VarInfoList.ContainsKey(varName))
                    {
                        VarInfo varInfo = VarInfoList[varName];
                        object  value   = ParseVariable(varInfo.Type, varNode.InnerText);
                        if (value is Exception)
                        {
                            parsingErrors.Add(varInfo.Type.ToString() + " " + varName + ": " + ((Exception)value).Message);
                        }
                        else
                        {
                            VarList.Add(varName, new Variable(varInfo, value));
                        }
                    }
                    else
                    {
                        unrecognized.Add(varName);
                    }
                }
                catch (KeyNotFoundException) {
                    unrecognized.Add(varName);
                }
                catch (ArgumentException) {
                    alreadyDefined.Add(varName);
                }
            }

            // Log errors
            if (unrecognized.Count > 0 || parsingErrors.Count > 0 || alreadyDefined.Count > 0)
            {
                if (!ErrorLogger.IsOpen)
                {
                    ErrorLogger.Open();
                }
                ErrorLogger.WriteErrorHeader();
                ErrorLogger.WriteLine("There were errors when reading ItemID: " + ID.ToString() + ".");
                if (looseText)
                {
                    ErrorLogger.WriteLine("Loose text is present inside the element.");
                }
                if (unrecognized.Count > 0)
                {
                    ErrorLogger.WriteLine();
                    ErrorLogger.WriteLine("Unrecognized Variables:");
                    foreach (string s in unrecognized)
                    {
                        ErrorLogger.WriteLine("- " + s);
                    }
                }
                if (parsingErrors.Count > 0)
                {
                    ErrorLogger.WriteLine();
                    ErrorLogger.WriteLine("Parsing Errors:");
                    foreach (string s in parsingErrors)
                    {
                        ErrorLogger.WriteLine("- " + s);
                    }
                }
                if (alreadyDefined.Count > 0)
                {
                    ErrorLogger.WriteLine();
                    ErrorLogger.WriteLine("Already Defined:");
                    foreach (string s in alreadyDefined)
                    {
                        ErrorLogger.WriteLine("- " + s);
                    }
                }
                ErrorLogger.WriteLine();
            }
        }
示例#8
0
        public override void Visit(UnionAllOp op, System.Data.Entity.Core.Query.InternalTrees.Node n)
        {
            this.VisitChildren(n);
            Var     var1     = (Var)this.m_command.CreateSetOpVar(this.m_command.IntegerType);
            VarList varList1 = Command.CreateVarList();

            VarVec[] varVecArray = new VarVec[n.Children.Count];
            for (int index = 0; index < n.Children.Count; ++index)
            {
                System.Data.Entity.Core.Query.InternalTrees.Node child = n.Children[index];
                VarVec v = this.m_command.GetExtendedNodeInfo(child).Keys.KeyVars.Remap((Dictionary <Var, Var>)op.VarMap[index]);
                varVecArray[index] = this.m_command.CreateVarVec(v);
                varVecArray[index].Minus(op.Outputs);
                if (OpType.UnionAll == child.Op.OpType)
                {
                    UnionAllOp op1 = (UnionAllOp)child.Op;
                    varVecArray[index].Clear(op1.BranchDiscriminator);
                }
                varList1.AddRange((IEnumerable <Var>)varVecArray[index]);
            }
            VarList varList2 = Command.CreateVarList();

            foreach (Var var2 in (List <Var>)varList1)
            {
                Var setOpVar = (Var)this.m_command.CreateSetOpVar(var2.Type);
                varList2.Add(setOpVar);
            }
            for (int index1 = 0; index1 < n.Children.Count; ++index1)
            {
                System.Data.Entity.Core.Query.InternalTrees.Node child = n.Children[index1];
                ExtendedNodeInfo extendedNodeInfo1 = this.m_command.GetExtendedNodeInfo(child);
                VarVec           varVec            = this.m_command.CreateVarVec();
                List <System.Data.Entity.Core.Query.InternalTrees.Node> args = new List <System.Data.Entity.Core.Query.InternalTrees.Node>();
                Var computedVar1;
                if (OpType.UnionAll == child.Op.OpType && ((UnionAllOp)child.Op).BranchDiscriminator != null)
                {
                    computedVar1 = ((UnionAllOp)child.Op).BranchDiscriminator;
                    if (!op.VarMap[index1].ContainsValue(computedVar1))
                    {
                        op.VarMap[index1].Add(var1, computedVar1);
                    }
                    else
                    {
                        System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(0 == index1, "right branch has a discriminator var that the left branch doesn't have?");
                        var1 = op.VarMap[index1].GetReverseMap()[computedVar1];
                    }
                }
                else
                {
                    args.Add(this.m_command.CreateVarDefNode(this.m_command.CreateNode((Op)this.m_command.CreateConstantOp(this.m_command.IntegerType, (object)this.m_command.NextBranchDiscriminatorValue)), out computedVar1));
                    varVec.Set(computedVar1);
                    op.VarMap[index1].Add(var1, computedVar1);
                }
                for (int index2 = 0; index2 < varList1.Count; ++index2)
                {
                    Var computedVar2 = varList1[index2];
                    if (!varVecArray[index1].IsSet(computedVar2))
                    {
                        args.Add(this.m_command.CreateVarDefNode(this.m_command.CreateNode((Op)this.m_command.CreateNullOp(computedVar2.Type)), out computedVar2));
                        varVec.Set(computedVar2);
                    }
                    op.VarMap[index1].Add(varList2[index2], computedVar2);
                }
                if (varVec.IsEmpty)
                {
                    extendedNodeInfo1.Keys.KeyVars.Set(computedVar1);
                }
                else
                {
                    System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(args.Count != 0, "no new nodes?");
                    foreach (Var v in op.VarMap[index1].Values)
                    {
                        varVec.Set(v);
                    }
                    n.Children[index1] = this.m_command.CreateNode((Op)this.m_command.CreateProjectOp(varVec), child, this.m_command.CreateNode((Op)this.m_command.CreateVarDefListOp(), args));
                    this.m_command.RecomputeNodeInfo(n.Children[index1]);
                    ExtendedNodeInfo extendedNodeInfo2 = this.m_command.GetExtendedNodeInfo(n.Children[index1]);
                    extendedNodeInfo2.Keys.KeyVars.InitFrom(extendedNodeInfo1.Keys.KeyVars);
                    extendedNodeInfo2.Keys.KeyVars.Set(computedVar1);
                }
            }
            n.Op = (Op)this.m_command.CreateUnionAllOp(op.VarMap[0], op.VarMap[1], var1);
            this.m_command.RecomputeNodeInfo(n);
        }