public static void VerifyEdmTypesEquivalent(LegacyMetadata.EdmType legacyEdmType, EdmType edmType) { Assert.Equal(legacyEdmType.FullName, edmType.FullName); Assert.True( (legacyEdmType.BaseType == null && edmType.BaseType == null) || legacyEdmType.BaseType.FullName == edmType.BaseType.FullName); Assert.Equal(legacyEdmType.BuiltInTypeKind.ToString(), edmType.BuiltInTypeKind.ToString()); Assert.Equal( ((LegacyMetadata.DataSpace)typeof(LegacyMetadata.EdmType) .GetProperty("DataSpace", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(legacyEdmType)).ToString(), ((DataSpace)typeof(EdmType) .GetProperty("DataSpace", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(edmType)).ToString()); if (edmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveTypeKind) { var prmitiveEdmType = (PrimitiveType)edmType; var legacyPrmitiveEdmType = (LegacyMetadata.PrimitiveType)legacyEdmType; // EF5 geospatial types should be converted to EF6 spatial types var expectedClrEquivalentType = legacyPrmitiveEdmType.ClrEquivalentType == typeof(LegacySpatial.DbGeography) ? typeof(DbGeography) : legacyPrmitiveEdmType.ClrEquivalentType == typeof(LegacySpatial.DbGeometry) ? typeof(DbGeometry) : legacyPrmitiveEdmType.ClrEquivalentType; Assert.Equal(expectedClrEquivalentType, prmitiveEdmType.ClrEquivalentType); Assert.Equal(legacyPrmitiveEdmType.GetEdmPrimitiveType().FullName, prmitiveEdmType.GetEdmPrimitiveType().FullName); } }
public static void VerifyFacetsEquivalent(LegacyMetadata.Facet legacyFacet, Facet facet) { Assert.Equal(legacyFacet.Name, facet.Name); Assert.Equal(legacyFacet.FacetType.FullName, facet.FacetType.FullName); // Specialcase Variable, Max and Identity facet values - they are internal singleton objects. if (legacyFacet.Value != null && (new[] { "Max", "Variable", "Identity" }.Contains(legacyFacet.Value.ToString()) || facet.Name == "ConcurrencyMode")) { // this is to make sure we did not stick EF6 Max/Variable/Identity on legacy facet as the value Assert.Equal(typeof(LegacyMetadata.EdmType).Assembly, legacyFacet.Value.GetType().Assembly); Assert.NotNull(facet.Value); Assert.Equal(legacyFacet.Value.ToString(), facet.Value.ToString()); } else { Assert.Equal(legacyFacet.Value, facet.Value); } Assert.Equal(legacyFacet.IsUnbounded, facet.IsUnbounded); Assert.Equal(LegacyMetadata.BuiltInTypeKind.Facet, legacyFacet.BuiltInTypeKind); Assert.Equal(BuiltInTypeKind.Facet, facet.BuiltInTypeKind); }
/// <summary> /// Is this a structured type? /// Note: Structured, in this context means structured outside the server. /// UDTs for instance, are considered to be scalar types - all WinFS types, /// would by this argument, be scalar types. /// </summary> /// <param name="type">The type to check</param> /// <returns>true, if the type is a structured type</returns> internal static bool IsStructuredType(md.TypeUsage type) { return (md.TypeSemantics.IsReferenceType(type) || md.TypeSemantics.IsRowType(type) || md.TypeSemantics.IsEntityType(type) || md.TypeSemantics.IsRelationshipType(type) || (md.TypeSemantics.IsComplexType(type))); }
/// <summary> /// Is there a parent child relationship between table1 and table2 ? /// </summary> /// <param name="table1">parent table ?</param> /// <param name="table2">child table ?</param> /// <param name="constraints">list of constraints ?</param> /// <returns>true if there is at least one constraint</returns> internal bool IsParentChildRelationship( md.EntitySetBase table1, md.EntitySetBase table2, out List<ForeignKeyConstraint> constraints) { LoadRelationships(table1.EntityContainer); LoadRelationships(table2.EntityContainer); var extentPair = new ExtentPair(table1, table2); return m_parentChildRelationships.TryGetValue(extentPair, out constraints); }
protected TypeInfo(md.TypeUsage type, TypeInfo superType) { m_type = type; m_immediateSubTypes = new List<TypeInfo>(); m_superType = superType; if (superType != null) { // Add myself to my supertype's list of subtypes superType.m_immediateSubTypes.Add(this); // my supertype's root type is mine as well m_rootType = superType.RootType; } }
private readonly RootTypeInfo m_rootType; // the top-most type in this types type hierarchy #endregion #region Constructors and factory methods /// <summary> /// Creates type information for a type /// </summary> /// <param name="type"></param> /// <param name="superTypeInfo"></param> /// <returns></returns> internal static TypeInfo Create(md.TypeUsage type, TypeInfo superTypeInfo, ExplicitDiscriminatorMap discriminatorMap) { TypeInfo result; if (superTypeInfo == null) { result = new RootTypeInfo(type, discriminatorMap); } else { result = new TypeInfo(type, superTypeInfo); } return result; }
/// <summary> /// Load all relationships in this entity container /// </summary> /// <param name="entityContainer"></param> internal void LoadRelationships(md.EntityContainer entityContainer) { // Check to see if I've already loaded information for this entity container if (m_entityContainerMap.ContainsKey(entityContainer)) { return; } // Load all relationships from this entitycontainer foreach (var e in entityContainer.BaseEntitySets) { var relationshipSet = e as md.RelationshipSet; if (relationshipSet == null) { continue; } // Relationship sets can only contain relationships var relationshipType = relationshipSet.ElementType; var assocType = relationshipType as md.AssociationType; // // Handle only binary Association relationships for now // if (null == assocType || !IsBinary(relationshipType)) { continue; } foreach (var constraint in assocType.ReferentialConstraints) { List<ForeignKeyConstraint> fkConstraintList; var fkConstraint = new ForeignKeyConstraint(relationshipSet, constraint); if (!m_parentChildRelationships.TryGetValue(fkConstraint.Pair, out fkConstraintList)) { fkConstraintList = new List<ForeignKeyConstraint>(); m_parentChildRelationships[fkConstraint.Pair] = fkConstraintList; } // // Theoretically, we can have more than one fk constraint between // the 2 tables (though, it is unlikely) // fkConstraintList.Add(fkConstraint); } } // Mark this entity container as already loaded m_entityContainerMap[entityContainer] = entityContainer; }
public static void VerifyTypeUsagesEquivalent(LegacyMetadata.TypeUsage legacyTypeUsage, TypeUsage typeUsage) { if (typeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType) { VerifyTypeUsagesEquivalent( ((LegacyMetadata.CollectionType)legacyTypeUsage.EdmType).TypeUsage, ((CollectionType)typeUsage.EdmType).TypeUsage); } else { VerifyEdmTypesEquivalent(legacyTypeUsage.EdmType, typeUsage.EdmType); } var legacyTypeFacets = legacyTypeUsage.Facets.OrderBy(f => f.Name).ToArray(); var typeFacets = typeUsage.Facets.OrderBy(f => f.Name).ToArray(); Assert.Equal(legacyTypeFacets.Length, typeFacets.Length); for (var i = 0; i < legacyTypeFacets.Length; i++) { VerifyFacetsEquivalent(legacyTypeFacets[i], typeFacets[i]); } }
private static Dictionary<Var, md.EdmProperty> BuildOutputVarMap(PhysicalProjectOp projectOp, md.TypeUsage outputType) { var outputVarMap = new Dictionary<Var, md.EdmProperty>(); PlanCompiler.Assert(md.TypeSemantics.IsRowType(outputType), "PhysicalProjectOp result type is not a RowType?"); IEnumerator<md.EdmProperty> propertyEnumerator = TypeHelpers.GetEdmType<md.RowType>(outputType).Properties.GetEnumerator(); IEnumerator<Var> varEnumerator = projectOp.Outputs.GetEnumerator(); while (true) { var foundProp = propertyEnumerator.MoveNext(); var foundVar = varEnumerator.MoveNext(); if (foundProp != foundVar) { throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.ColumnCountMismatch, 1, null); } if (!foundProp) { break; } outputVarMap[varEnumerator.Current] = propertyEnumerator.Current; } return outputVarMap; }
/// <summary> /// Is this type an enum type? /// </summary> /// <param name="type">the current type</param> /// <returns>true, if this is an enum type</returns> internal static bool IsEnumerationType(md.TypeUsage type) { return md.TypeSemantics.IsEnumerationType(type); }
/// <summary> /// Build out an EntityIdentity structure - for use by EntityColumnMap and RefColumnMap /// </summary> /// <param name="entityType">the entity type in question</param> /// <param name="entitySetIdColumnMap">column map for the entitysetid column</param> /// <param name="keyColumnMaps">column maps for the keys</param> /// <returns></returns> private EntityIdentity CreateEntityIdentity(md.EntityType entityType, SimpleColumnMap entitySetIdColumnMap, SimpleColumnMap[] keyColumnMaps) { // // If we have an entitysetid (and therefore, a column map for the entitysetid), // then use a discriminated entity identity; otherwise, we use a simpleentityidentity // instead // if (entitySetIdColumnMap != null) { return new DiscriminatedEntityIdentity(entitySetIdColumnMap, m_typeInfo.EntitySetIdToEntitySetMap, keyColumnMaps); } else { md.EntitySet entitySet = m_typeInfo.GetEntitySet(entityType); PlanCompiler.Assert(entitySet != null, "Expected non-null entityset when no entitysetid is required. Entity type = " + entityType); return new SimpleEntityIdentity(entitySet, keyColumnMaps); } }
/// <summary> /// Create a column map for the typeid column /// </summary> /// <param name="prop"></param> /// <returns></returns> private SimpleColumnMap CreateTypeIdColumnMap(md.EdmProperty prop) { return CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(prop), c_TypeIdColumnName); }
/// <summary> /// Helps flatten out a computedVar expression /// </summary> /// <param name="v">The Var</param> /// <param name="node">Subtree rooted at the VarDefOp expression</param> /// <param name="newNodes">list of new nodes produced</param> /// <param name="newType"></param> /// <returns>VarInfo for this var</returns> private void FlattenComputedVar(ComputedVar v, Node node, out List<Node> newNodes, out md.TypeUsage newType) { newNodes = new List<Node>(); Node definingExprNode = node.Child0; // defining expression for the VarDefOp newType = null; if (TypeUtils.IsCollectionType(v.Type)) { PlanCompiler.Assert(definingExprNode.Op.OpType != OpType.Function, "Flattening of TVF output is not allowed."); newType = GetNewType(v.Type); Var newVar; Node newVarDefNode = m_command.CreateVarDefNode(definingExprNode, out newVar); newNodes.Add(newVarDefNode); m_varInfoMap.CreateCollectionVarInfo(v, newVar); return; } // Get the "new" type for the Var TypeInfo typeInfo = m_typeInfo.GetTypeInfo(v.Type); // Get a list of properties that we think are necessary PropertyRefList desiredProperties = m_varPropertyMap[v]; List<Var> newVars = new List<Var>(); List<md.EdmProperty> newProps = new List<md.EdmProperty>(); newNodes = new List<Node>(); var hasNullSentinelVar = false; foreach (PropertyRef p in typeInfo.PropertyRefList) { // do I care for this property? if (!desiredProperties.Contains(p)) { continue; } md.EdmProperty newProperty = typeInfo.GetNewProperty(p); // // #479467 - Make sure that we build Vars for all properties - if // we are asked to produce all properties. This is extremely important // for the top-level Vars // Node propAccessor = null; if (desiredProperties.AllProperties) { propAccessor = BuildAccessorWithNulls(definingExprNode, newProperty); } else { propAccessor = BuildAccessor(definingExprNode, newProperty); if (propAccessor == null) { continue; } } // Add the new property newProps.Add(newProperty); // Create a new VarDefOp. Var newVar; Node newVarDefNode = m_command.CreateVarDefNode(propAccessor, out newVar); newNodes.Add(newVarDefNode); newVars.Add(newVar); // Check if it is a null sentinel var if (!hasNullSentinelVar && IsNullSentinelPropertyRef(p)) { hasNullSentinelVar = true; } } m_varInfoMap.CreateStructuredVarInfo(v, typeInfo.FlattenedType, newVars, newProps, hasNullSentinelVar); return; }
/// <summary> /// Returns a node for a null constant of the desired type /// </summary> /// <param name="type"></param> /// <returns></returns> private Node CreateNullConstantNode(md.TypeUsage type) { return m_command.CreateNode(m_command.CreateNullOp(type)); }
/// <summary> /// Get the Var corresponding to a specific property /// </summary> /// <param name="p">the requested property</param> /// <param name="v">the corresponding Var</param> /// <returns>true, if the Var was found</returns> internal bool TryGetVar(md.EdmProperty p, out Var v) { if (m_propertyToVarMap == null) { InitPropertyToVarMap(); } return m_propertyToVarMap.TryGetValue(p, out v); }
/// <summary> /// A BuildAccessor variant. If the appropriate property was not found, then /// build up a null constant instead /// </summary> /// <param name="input"></param> /// <param name="property"></param> /// <returns></returns> private Node BuildAccessorWithNulls(Node input, md.EdmProperty property) { Node newNode = this.BuildAccessor(input, property); if (newNode == null) { newNode = CreateNullConstantNode(md.Helper.GetModelTypeUsage(property)); } return newNode; }
/// <summary> /// Builds a SoftCast operator over the input - if one is necessary. /// </summary> /// <param name="node">the input expression to "cast"</param> /// <param name="targetType">the target type</param> /// <returns>the "cast"ed expression</returns> private Node BuildSoftCast(Node node, md.TypeUsage targetType) { PlanCompiler.Assert(node.Op.IsScalarOp, "Attempting SoftCast around non-ScalarOp?"); if (Command.EqualTypes(node.Op.Type, targetType)) { return node; } // Skip any castOps we may have created already while (node.Op.OpType == OpType.SoftCast) { node = node.Child0; } Node newNode = m_command.CreateNode(m_command.CreateSoftCastOp(targetType), node); return newNode; }
/// <summary> /// Create a new VarInfo for a structured type Var /// </summary> /// <param name="v">The structured type Var</param> /// <param name="newType">"Mapped" type for v</param> /// <param name="newVars">List of vars corresponding to v</param> /// <param name="newProperties">Flattened Properties </param> /// <param name="newVarsIncludeNullSentinelVar">Do the new vars include a var that represents a null sentinel either for this type or for any nested type</param> /// <returns>the VarInfo</returns> internal VarInfo CreateStructuredVarInfo(Var v, md.RowType newType, List<Var> newVars, List<md.EdmProperty> newProperties, bool newVarsIncludeNullSentinelVar) { VarInfo varInfo = new StructuredVarInfo(newType, newVars, newProperties, newVarsIncludeNullSentinelVar); m_map.Add(v, varInfo); return varInfo; }
/// <summary> /// Build up a key-value pair of (property, expression) to represent /// the extraction of the appropriate property from the input expression /// </summary> /// <param name="input">The input (structured type) expression</param> /// <param name="property">The property in question</param> /// <param name="ignoreMissingProperties">should we ignore missing properties</param> /// <returns></returns> private KeyValuePair<md.EdmProperty, Node> GetPropertyValue(Node input, md.EdmProperty property, bool ignoreMissingProperties) { Node n = null; if (!ignoreMissingProperties) { n = BuildAccessorWithNulls(input, property); } else { n = BuildAccessor(input, property); } return new KeyValuePair<md.EdmProperty, Node>(property, n); }
/// <summary> /// Create a new VarInfo for a structured type Var where the newVars cannot include a null sentinel /// </summary> /// <param name="v">The structured type Var</param> /// <param name="newType">"Mapped" type for v</param> /// <param name="newVars">List of vars corresponding to v</param> /// <param name="newProperties">Flattened Properties </param> internal VarInfo CreateStructuredVarInfo(Var v, md.RowType newType, List<Var> newVars, List<md.EdmProperty> newProperties) { return CreateStructuredVarInfo(v, newType, newVars, newProperties, false); }
/// <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; }
private IEnumerable<md.EdmProperty> GetTvfResultKeys(md.EdmFunction tvf) { md.EdmProperty[] keys; if (m_tvfResultKeys.TryGetValue(tvf, out keys)) { return keys; } return Enumerable.Empty<md.EdmProperty>(); }
/// <summary> /// Create a column map for a structural column - ref/complextype/entity/record /// </summary> /// <param name="type">Type info for the type</param> /// <param name="name">column name</param> /// <returns></returns> private ColumnMap CreateStructuralColumnMap(md.TypeUsage type, string name) { // Get our augmented type information for this type TypeInfo typeInfo = m_typeInfo.GetTypeInfo(type); // records? if (md.TypeSemantics.IsRowType(type)) { return CreateRecordColumnMap(typeInfo, name); } // ref? if (md.TypeSemantics.IsReferenceType(type)) { return CreateRefColumnMap(typeInfo, name); } // polymorphic type? if (typeInfo.HasTypeIdProperty) { return CreatePolymorphicColumnMap(typeInfo, name); } // process complex/entity types appropriately if (md.TypeSemantics.IsComplexType(type)) { return CreateComplexTypeColumnMap(typeInfo, name, null, null, null); } if (md.TypeSemantics.IsEntityType(type)) { return CreateEntityColumnMap(typeInfo, name, null, null, null, true); } // Anything else is not supported (this currently includes relationship types) throw EntityUtil.NotSupported(type.Identity); }
private Node RewriteAsCastToUnderlyingType(md.PrimitiveType underlyingType, CastOp op, Node n) { // if type of the argument and the underlying type match we can strip the Cast entirely if (underlyingType.PrimitiveTypeKind == ((md.PrimitiveType)n.Child0.Op.Type.EdmType).PrimitiveTypeKind) { return n.Child0; } else { return m_command.CreateNode(m_command.CreateCastOp(md.TypeUsage.Create(underlyingType, op.Type.Facets)), n.Child0); } }
/// <summary> /// Creates a column map for a column /// </summary> /// <param name="type">column datatype</param> /// <param name="name">column name</param> /// <returns></returns> private ColumnMap CreateColumnMap(md.TypeUsage type, string name) { // For simple types, create a simple column map // Temporarily, handle collections exactly the same way if (!TypeUtils.IsStructuredType(type)) { return CreateSimpleColumnMap(type, name); } // At this point, we must be dealing with either a record type, a // complex type, or an entity type return CreateStructuralColumnMap(type, name); }
/// <summary> /// Get the "new" type corresponding to the input type. /// For structured types, we simply look up the typeInfoMap /// For collection types, we create a new collection type based on the /// "new" element type. /// For enums we return the underlying type of the enum type. /// For strong spatial types we return the union type that includes the strong spatial type. /// For all other types, we simply return the input type /// </summary> /// <param name="type"></param> /// <returns></returns> private md.TypeUsage GetNewType(md.TypeUsage type) { md.TypeUsage newType; if (m_typeToNewTypeMap.TryGetValue(type, out newType)) { return newType; } md.CollectionType collectionType; if (TypeHelpers.TryGetEdmType<md.CollectionType>(type, out collectionType)) { // If this is a collection type, then clone a new collection type md.TypeUsage newElementType = GetNewType(collectionType.TypeUsage); newType = TypeUtils.CreateCollectionType(newElementType); } else if (TypeUtils.IsStructuredType(type)) { // structured type => we've already calculated the input newType = m_typeInfo.GetTypeInfo(type).FlattenedTypeUsage; } else if (md.TypeSemantics.IsEnumerationType(type)) { newType = TypeHelpers.CreateEnumUnderlyingTypeUsage(type); } else if (md.TypeSemantics.IsStrongSpatialType(type)) { newType = TypeHelpers.CreateSpatialUnionTypeUsage(type); } else { // "simple" type => return the input type newType = type; } // Add this information to the map m_typeToNewTypeMap[type] = newType; return newType; }
/// <summary> /// Is this type a collection type? /// </summary> /// <param name="type">the current type</param> /// <returns>true, if this is a collection type</returns> internal static bool IsCollectionType(md.TypeUsage type) { return md.TypeSemantics.IsCollectionType(type); }
/// <summary> /// Build out an expression corresponding to the entitysetid /// </summary> /// <param name="entitySetidProperty">the property corresponding to the entitysetid</param> /// <param name="op">the *NewEntity op</param> /// <returns></returns> private Node GetEntitySetIdExpr(md.EdmProperty entitySetIdProperty, NewEntityBaseOp op) { Node entitySetIdNode; md.EntitySet entitySet = op.EntitySet as md.EntitySet; if (entitySet != null) { int entitySetId = m_typeInfo.GetEntitySetId(entitySet); InternalConstantOp entitySetIdOp = m_command.CreateInternalConstantOp(md.Helper.GetModelTypeUsage(entitySetIdProperty), entitySetId); entitySetIdNode = m_command.CreateNode(entitySetIdOp); } else { // // Not in a view context; simply assume a null entityset // entitySetIdNode = CreateNullConstantNode(md.Helper.GetModelTypeUsage(entitySetIdProperty)); } return entitySetIdNode; }
/// <summary> /// Create a new collection type based on the supplied element type /// </summary> /// <param name="elementType">element type of the collection</param> /// <returns>the new collection type</returns> internal static md.TypeUsage CreateCollectionType(md.TypeUsage elementType) { return TypeHelpers.CreateCollectionTypeUsage(elementType); }
/// <summary> /// This function builds a "property accessor" over the input expression. It /// can produce one of three results: /// /// - It can return "null", if it is convinced that the input has no /// such expression /// - It can return a subnode of the input, if that subnode represents /// the property /// - Or, it can build a PropertyOp explicitly /// /// Assertion: the property is not a structured type /// </summary> /// <param name="input">The input expression</param> /// <param name="property">The desired property</param> /// <returns></returns> private Node BuildAccessor(Node input, md.EdmProperty property) { Op inputOp = input.Op; // Special handling if the input is a NewRecordOp NewRecordOp newRecordOp = inputOp as NewRecordOp; if (null != newRecordOp) { int fieldPos; // Identify the specific property we're interested in. if (newRecordOp.GetFieldPosition(property, out fieldPos)) { return Copy(input.Children[fieldPos]); } else { return null; } } // special handling if the input is a null if (inputOp.OpType == OpType.Null) { return null; } // The default case: Simply return a new PropertyOp PropertyOp newPropertyOp = m_command.CreatePropertyOp(property); return m_command.CreateNode(newPropertyOp, this.Copy(input)); }