/// <summary> /// Replace VarRefColumnMaps with ScalarColumnMaps referring to the command and column /// </summary> /// <param name="columnMapToTranslate"></param> /// <param name="varToCommandColumnMap"></param> /// <returns></returns> internal static ColumnMap Translate(ColumnMap columnMapToTranslate, Dictionary <Var, KeyValuePair <int, int> > varToCommandColumnMap) { ColumnMap result = Translate(columnMapToTranslate, delegate(ColumnMap columnMap) { VarRefColumnMap varRefColumnMap = columnMap as VarRefColumnMap; if (null != varRefColumnMap) { KeyValuePair <int, int> commandAndColumn; if (!varToCommandColumnMap.TryGetValue(varRefColumnMap.Var, out commandAndColumn)) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.UnknownVar, 1, varRefColumnMap.Var.Id); // shouldn't have gotten here without having a resolveable var } columnMap = new ScalarColumnMap(varRefColumnMap.Type, varRefColumnMap.Name, commandAndColumn.Key, commandAndColumn.Value); } // While we're at it, we ensure that all columnMaps are named; we wait // until this point, because we don't want to assign names until after // we've gone through the transformations; if (!columnMap.IsNamed) { columnMap.Name = ColumnMap.DefaultColumnName; } return(columnMap); } ); return(result); }
/// <summary> /// Replace VarRefColumnMaps with the specified ColumnMap replacement /// </summary> /// <param name="columnMapToTranslate"></param> /// <param name="varToColumnMap"></param> /// <returns></returns> internal static ColumnMap Translate(ColumnMap columnMapToTranslate, Dictionary <Var, ColumnMap> varToColumnMap) { ColumnMap result = Translate(columnMapToTranslate, delegate(ColumnMap columnMap) { VarRefColumnMap varRefColumnMap = columnMap as VarRefColumnMap; if (null != varRefColumnMap) { if (varToColumnMap.TryGetValue(varRefColumnMap.Var, out columnMap)) { // perform fixups; only allow name changes when the replacement isn't // already named (and the original is named...) if (!columnMap.IsNamed && varRefColumnMap.IsNamed) { columnMap.Name = varRefColumnMap.Name; } } else { columnMap = varRefColumnMap; } } return(columnMap); } ); return(result); }
internal override void Visit( VarRefColumnMap columnMap, HashSet <string> typesNeedingNullSentinel) { StructuredTypeNullabilityAnalyzer.AddTypeNeedingNullSentinel(typesNeedingNullSentinel, columnMap.Type); base.Visit(columnMap, typesNeedingNullSentinel); }
// <summary> // Create a simple columnmap - applies only to scalar properties // (Temporarily, also for collections) // Simply picks up the next available column in the reader // </summary> // <param name="type"> Column type </param> // <param name="name"> column name </param> // <returns> Column map for this column </returns> private SimpleColumnMap CreateSimpleColumnMap(md.TypeUsage type, string name) { var newVar = GetNextVar(); SimpleColumnMap result = new VarRefColumnMap(type, name, newVar); return(result); }
internal static ColumnMap Translate( ColumnMap columnMapToTranslate, Dictionary <Var, ColumnMap> varToColumnMap) { return(ColumnMapTranslator.Translate(columnMapToTranslate, (ColumnMapTranslatorTranslationDelegate)(columnMap => { VarRefColumnMap varRefColumnMap = columnMap as VarRefColumnMap; if (varRefColumnMap != null) { if (varToColumnMap.TryGetValue(varRefColumnMap.Var, out columnMap)) { if (!columnMap.IsNamed && varRefColumnMap.IsNamed) { columnMap.Name = varRefColumnMap.Name; } if (Helper.IsEnumType(varRefColumnMap.Type.EdmType) && varRefColumnMap.Type.EdmType != columnMap.Type.EdmType) { columnMap.Type = varRefColumnMap.Type; } } else { columnMap = (ColumnMap)varRefColumnMap; } } return columnMap; }))); }
internal ColumnMapProcessor(VarRefColumnMap columnMap, VarInfo varInfo, StructuredTypeInfo typeInfo) { m_columnMap = columnMap; m_varInfo = varInfo; PlanCompiler.Assert(varInfo.NewVars != null && varInfo.NewVars.Count > 0, "No new Vars specified"); m_varList = varInfo.NewVars.GetEnumerator(); m_typeInfo = typeInfo; }
internal ColumnMapProcessor( VarRefColumnMap columnMap, VarInfo varInfo, StructuredTypeInfo typeInfo) { this.m_columnMap = columnMap; this.m_varInfo = varInfo; System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(varInfo.NewVars != null && varInfo.NewVars.Count > 0, "No new Vars specified"); this.m_varList = (IEnumerator <Var>)varInfo.NewVars.GetEnumerator(); this.m_typeInfo = typeInfo; }
internal static ColumnMap Translate( ColumnMap columnMapToTranslate, Dictionary <Var, Var> varToVarMap) { return(ColumnMapTranslator.Translate(columnMapToTranslate, (ColumnMapTranslatorTranslationDelegate)(columnMap => { VarRefColumnMap varRefColumnMap = columnMap as VarRefColumnMap; if (varRefColumnMap != null) { Var replacementVar = ColumnMapTranslator.GetReplacementVar(varRefColumnMap.Var, varToVarMap); if (varRefColumnMap.Var != replacementVar) { columnMap = (ColumnMap) new VarRefColumnMap(varRefColumnMap.Type, varRefColumnMap.Name, replacementVar); } } return columnMap; }))); }
/// <summary> /// Replace VarRefColumnMaps with new VarRefColumnMaps with the specified Var /// </summary> /// <param name="columnMapToTranslate"></param> /// <param name="varToVarMap"></param> /// <returns></returns> internal static ColumnMap Translate(ColumnMap columnMapToTranslate, Dictionary <Var, Var> varToVarMap) { ColumnMap result = Translate(columnMapToTranslate, delegate(ColumnMap columnMap) { VarRefColumnMap varRefColumnMap = columnMap as VarRefColumnMap; if (null != varRefColumnMap) { Var replacementVar = GetReplacementVar(varRefColumnMap.Var, varToVarMap); if (varRefColumnMap.Var != replacementVar) { columnMap = new VarRefColumnMap(varRefColumnMap.Type, varRefColumnMap.Name, replacementVar); } } return(columnMap); } ); return(result); }
public void Translate_preserves_column_type() { var intTypeUsage = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); var enumTypeUsage = TypeUsage.CreateDefaultTypeUsage( new EnumType("ns", "DayOfWeek", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32), false, DataSpace.CSpace)); var originalVar = new ComputedVar(42, intTypeUsage); var originalColumnMap = new VarRefColumnMap(enumTypeUsage, "dayOfWeek", originalVar); var replacementVar = new ComputedVar(911, intTypeUsage); var replacementColumnMap = new VarRefColumnMap(intTypeUsage, null, replacementVar); var varToColumnMap = new Dictionary<Var, ColumnMap> { { originalVar, replacementColumnMap } }; var resultColumnMap = ColumnMapTranslator.Translate(originalColumnMap, varToColumnMap); Assert.Same(replacementColumnMap, resultColumnMap); Assert.Equal(originalColumnMap.Name, resultColumnMap.Name); Assert.Equal(originalColumnMap.Type.EdmType, resultColumnMap.Type.EdmType); }
internal static ColumnMap Translate( ColumnMap columnMapToTranslate, Dictionary <Var, KeyValuePair <int, int> > varToCommandColumnMap) { return(ColumnMapTranslator.Translate(columnMapToTranslate, (ColumnMapTranslatorTranslationDelegate)(columnMap => { VarRefColumnMap varRefColumnMap = columnMap as VarRefColumnMap; if (varRefColumnMap != null) { KeyValuePair <int, int> keyValuePair; if (!varToCommandColumnMap.TryGetValue(varRefColumnMap.Var, out keyValuePair)) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.UnknownVar, 1, (object)varRefColumnMap.Var.Id); } columnMap = (ColumnMap) new ScalarColumnMap(varRefColumnMap.Type, varRefColumnMap.Name, keyValuePair.Key, keyValuePair.Value); } if (!columnMap.IsNamed) { columnMap.Name = "Value"; } return columnMap; }))); }
public void Translate_preserves_column_type() { var intTypeUsage = TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32)); var enumTypeUsage = TypeUsage.CreateDefaultTypeUsage( new EnumType("ns", "DayOfWeek", PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.Int32), false, DataSpace.CSpace)); var originalVar = new ComputedVar(42, intTypeUsage); var originalColumnMap = new VarRefColumnMap(enumTypeUsage, "dayOfWeek", originalVar); var replacementVar = new ComputedVar(911, intTypeUsage); var replacementColumnMap = new VarRefColumnMap(intTypeUsage, null, replacementVar); var varToColumnMap = new Dictionary <Var, ColumnMap> { { originalVar, replacementColumnMap } }; var resultColumnMap = ColumnMapTranslator.Translate(originalColumnMap, varToColumnMap); Assert.Same(replacementColumnMap, resultColumnMap); Assert.Equal(originalColumnMap.Name, resultColumnMap.Name); Assert.Equal(originalColumnMap.Type.EdmType, resultColumnMap.Type.EdmType); }
/// <summary> /// VarRefColumnMap /// </summary> /// <param name="columnMap"></param> /// <param name="translationDelegate"></param> /// <returns></returns> internal override ColumnMap Visit(VarRefColumnMap columnMap, ColumnMapTranslatorTranslationDelegate translationDelegate) { return(translationDelegate(columnMap)); }
internal virtual void Visit(VarRefColumnMap columnMap, TArgType arg) { }
// <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; }
/// <summary> /// VarRefColumnMap /// </summary> /// <param name="columnMap"> </param> /// <param name="typesNeedingNullSentinel"> </param> /// <returns> </returns> internal override void Visit(VarRefColumnMap columnMap, HashSet <string> typesNeedingNullSentinel) { AddTypeNeedingNullSentinel(typesNeedingNullSentinel, columnMap.Type); base.Visit(columnMap, typesNeedingNullSentinel); }
internal abstract TResultType Visit(VarRefColumnMap columnMap, TArgType arg);
internal override void Visit(VarRefColumnMap columnMap, VarVec arg) { arg.Set(columnMap.Var); base.Visit(columnMap, arg); }
internal override void Visit(VarRefColumnMap columnMap, int dummy) { Debug.Fail("must not encounter VarRef in ColumnMap for key (eliminated in final ColumnMap)"); }
/// <summary> /// Create a simple columnmap - applies only to scalar properties /// (Temporarily, also for collections) /// Simply picks up the next available column in the reader /// </summary> /// <param name="type">Column type</param> /// <param name="name">column name</param> /// <returns>Column map for this column</returns> private SimpleColumnMap CreateSimpleColumnMap(md.TypeUsage type, string name) { Var newVar = GetNextVar(); SimpleColumnMap result = new VarRefColumnMap(type, name, newVar); return result; }
/// <summary> /// Create a physicalProjectOp - with a single column output /// </summary> /// <param name="outputVar">the output element</param> /// <returns></returns> internal PhysicalProjectOp CreatePhysicalProjectOp(Var outputVar) { VarList varList = Command.CreateVarList(); varList.Add(outputVar); VarRefColumnMap varRefColumnMap = new VarRefColumnMap(outputVar); SimpleCollectionColumnMap collectionColumnMap = new SimpleCollectionColumnMap( TypeUtils.CreateCollectionType(varRefColumnMap.Type), // type null, // name varRefColumnMap, // element map new SimpleColumnMap[0], // keys new SimpleColumnMap[0]); // foreign keys return CreatePhysicalProjectOp(varList, collectionColumnMap); }
internal override void Visit(VarRefColumnMap columnMap, int dummy) { }