Пример #1
0
 internal override void Visit(DiscriminatedCollectionColumnMap columnMap, int dummy)
 {
     Append("DC-D", columnMap.Discriminator);
     AppendValue(",DV", columnMap.DiscriminatorValue);
     Append(",FK", columnMap.ForeignKeys);
     Append(",K", columnMap.Keys);
     Append(",E", columnMap.Element);
 }
 internal override void Visit(DiscriminatedCollectionColumnMap columnMap, int dummy)
 {
     this.Append("DC-D", (ColumnMap)columnMap.Discriminator);
     this.AppendValue(",DV", columnMap.DiscriminatorValue);
     this.Append(",FK", (IEnumerable <ColumnMap>)columnMap.ForeignKeys);
     this.Append(",K", (IEnumerable <ColumnMap>)columnMap.Keys);
     this.Append(",E", columnMap.Element);
 }
Пример #3
0
 internal virtual void Visit(DiscriminatedCollectionColumnMap columnMap, TArgType arg)
 {
     columnMap.Discriminator.Accept(this, arg);
     foreach (var fk in columnMap.ForeignKeys)
     {
         fk.Accept(this, arg);
     }
     foreach (var k in columnMap.Keys)
     {
         k.Accept(this, arg);
     }
     columnMap.Element.Accept(this, arg);
 }
 internal virtual void Visit(DiscriminatedCollectionColumnMap columnMap, TArgType arg)
 {
     columnMap.Discriminator.Accept <TArgType>(this, arg);
     foreach (ColumnMap foreignKey in columnMap.ForeignKeys)
     {
         foreignKey.Accept <TArgType>(this, arg);
     }
     foreach (ColumnMap key in columnMap.Keys)
     {
         key.Accept <TArgType>(this, arg);
     }
     columnMap.Element.Accept <TArgType>(this, arg);
 }
Пример #5
0
        /// <summary>
        /// DiscriminatedCollectionColumnMap
        /// </summary>
        /// <param name="columnMap"></param>
        /// <param name="translationDelegate"></param>
        /// <returns></returns>
        internal override ColumnMap Visit(DiscriminatedCollectionColumnMap columnMap, ColumnMapTranslatorTranslationDelegate translationDelegate)
        {
            ColumnMap newDiscriminator = columnMap.Discriminator.Accept(this, translationDelegate);

            VisitList(columnMap.ForeignKeys, translationDelegate);
            VisitList(columnMap.Keys, translationDelegate);
            ColumnMap newElement = columnMap.Element.Accept(this, translationDelegate);

            if (newDiscriminator != columnMap.Discriminator || newElement != columnMap.Element)
            {
                columnMap = new DiscriminatedCollectionColumnMap(columnMap.Type, columnMap.Name, newElement, columnMap.Keys, columnMap.ForeignKeys, (SimpleColumnMap)newDiscriminator, columnMap.DiscriminatorValue);
            }
            return(translationDelegate(columnMap));
        }
Пример #6
0
        internal override ColumnMap Visit(
            DiscriminatedCollectionColumnMap columnMap,
            ColumnMapTranslatorTranslationDelegate translationDelegate)
        {
            ColumnMap columnMap1 = columnMap.Discriminator.Accept <ColumnMap, ColumnMapTranslatorTranslationDelegate>((ColumnMapVisitorWithResults <ColumnMap, ColumnMapTranslatorTranslationDelegate>) this, translationDelegate);

            this.VisitList <SimpleColumnMap>(columnMap.ForeignKeys, translationDelegate);
            this.VisitList <SimpleColumnMap>(columnMap.Keys, translationDelegate);
            ColumnMap elementMap = columnMap.Element.Accept <ColumnMap, ColumnMapTranslatorTranslationDelegate>((ColumnMapVisitorWithResults <ColumnMap, ColumnMapTranslatorTranslationDelegate>) this, translationDelegate);

            if (columnMap1 != columnMap.Discriminator || elementMap != columnMap.Element)
            {
                columnMap = new DiscriminatedCollectionColumnMap(columnMap.Type, columnMap.Name, elementMap, columnMap.Keys, columnMap.ForeignKeys, (SimpleColumnMap)columnMap1, columnMap.DiscriminatorValue);
            }
            return(translationDelegate((ColumnMap)columnMap));
        }
Пример #7
0
        public void TranslateColumnMap_returns_correct_columntypes_and_nullablecolumns_for_discriminated_collections()
        {
            var metadataWorkspaceMock = new Mock <MetadataWorkspace>();

            metadataWorkspaceMock.Setup(m => m.GetQueryCacheManager()).Returns(QueryCacheManager.Create());

            var entityColumnMap = (EntityColumnMap)BuildSimpleEntitySetColumnMap(metadataWorkspaceMock).Element;

            var collectionMap = new DiscriminatedCollectionColumnMap(
                entityColumnMap.Type, "MockCollectionType", entityColumnMap, null, null,
                new ScalarColumnMap(TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Boolean)), "discriminator", 0, 2),
                true);

            var factory =
                new Translator().TranslateColumnMap <object>(
                    collectionMap, metadataWorkspaceMock.Object, new SpanIndex(), MergeOption.NoTracking, streaming: false, valueLayer: false);

            Assert.NotNull(factory);

            Assert.Equal(new[] { typeof(int), typeof(int), typeof(bool) }, factory.ColumnTypes);
            Assert.Equal(new[] { true, true, true }, factory.NullableColumns);
        }
Пример #8
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;
        }
Пример #9
0
 internal abstract TResultType Visit(DiscriminatedCollectionColumnMap columnMap, TArgType arg);
Пример #10
0
        public void TranslateColumnMap_returns_correct_columntypes_and_nullablecolumns_for_discriminated_collections()
        {
            var metadataWorkspaceMock = new Mock<MetadataWorkspace>();
            metadataWorkspaceMock.Setup(m => m.GetQueryCacheManager()).Returns(QueryCacheManager.Create());

            var entityColumnMap = (EntityColumnMap)BuildSimpleEntitySetColumnMap(metadataWorkspaceMock).Element;

            var collectionMap = new DiscriminatedCollectionColumnMap(
                entityColumnMap.Type, "MockCollectionType", entityColumnMap, null, null,
                new ScalarColumnMap(TypeUsage.Create(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Boolean)), "discriminator", 0, 2),
                true);

            var factory =
                new Translator().TranslateColumnMap<object>(
                    collectionMap, metadataWorkspaceMock.Object, new SpanIndex(), MergeOption.NoTracking, streaming: false, valueLayer: false);
            Assert.NotNull(factory);

            Assert.Equal(new[] { typeof(int), typeof(int), typeof(bool) }, factory.ColumnTypes);
            Assert.Equal(new[] { true, true, true }, factory.NullableColumns);
        }