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; }
private EntityColumnMap CreateEntityColumnMap( TypeInfo typeInfo, string name, EntityColumnMap superTypeColumnMap, Dictionary<object, TypedColumnMap> discriminatorMap, List<TypedColumnMap> allMaps, bool handleRelProperties) { EntityColumnMap columnMap = null; var propertyColumnMapList = new List<ColumnMap>(); // Copy over information from my supertype if it already exists if (superTypeColumnMap != null) { // get supertype properties foreach (var c in superTypeColumnMap.Properties) { propertyColumnMapList.Add(c); } // Now add on all of my "specific" properties foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type)) { var propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name); propertyColumnMapList.Add(propertyColumnMap); } // create the entity column map w/ information from my supertype columnMap = new EntityColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), superTypeColumnMap.EntityIdentity); } else { SimpleColumnMap entitySetIdColumnMap = null; if (typeInfo.HasEntitySetIdProperty) { entitySetIdColumnMap = CreateEntitySetIdColumnMap(typeInfo.EntitySetIdProperty); } // build up a list of key columns var keyColumnMapList = new List<SimpleColumnMap>(); // Create a dictionary to look up the key properties var keyPropertyMap = new Dictionary<md.EdmProperty, ColumnMap>(); foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type)) { var propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name); propertyColumnMapList.Add(propertyColumnMap); // add property to keymap, if this property is part of the key if (md.TypeSemantics.IsPartOfKey(property)) { var edmProperty = property as md.EdmProperty; PlanCompiler.Assert(edmProperty != null, "EntityType key member is not property?"); keyPropertyMap[edmProperty] = propertyColumnMap; } } // Build up the key list if required foreach (var keyProperty in TypeHelpers.GetEdmType<md.EntityType>(typeInfo.Type).KeyMembers) { var edmKeyProperty = keyProperty as md.EdmProperty; PlanCompiler.Assert(edmKeyProperty != null, "EntityType key member is not property?"); var keyColumnMap = keyPropertyMap[edmKeyProperty] as SimpleColumnMap; PlanCompiler.Assert(keyColumnMap != null, "keyColumnMap is null"); keyColumnMapList.Add(keyColumnMap); } // // Create the entity identity. // var identity = CreateEntityIdentity((md.EntityType)typeInfo.Type.EdmType, entitySetIdColumnMap, keyColumnMapList.ToArray()); // finally create the entity column map columnMap = new EntityColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), identity); } // if a dictionary is supplied, add myself to the dictionary (abstract types need not be added) if (discriminatorMap != null) { // where DiscriminatedNewInstanceOp is used, there will not be an explicit type id for an abstract type // or types that do not appear in the QueryView // (the mapping will not include such information) if (null != typeInfo.TypeId) { discriminatorMap[typeInfo.TypeId] = columnMap; } } if (allMaps != null) { allMaps.Add(columnMap); } // Finally walk through my subtypes foreach (var subTypeInfo in typeInfo.ImmediateSubTypes) { CreateEntityColumnMap(subTypeInfo, name, columnMap, discriminatorMap, allMaps, false); } // // Build up the list of rel property column maps // if (handleRelProperties) { BuildRelPropertyColumnMaps(typeInfo, true); } return columnMap; }
/// <summary> /// Get a list of properties and value (expressions) for each desired property of the /// input. The list of desired properties is based on the opKind parameter. /// The ignoreMissingProperties indicates if we should create a null constant, in case /// the input cannot produce the specified property /// </summary> /// <param name="typeInfo"> typeinfo for the input </param> /// <param name="opKind"> Current operation kind </param> /// <param name="input"> The input expression tree </param> /// <param name="ignoreMissingProperties"> Should we ignore missing properties </param> /// <param name="properties"> Output: list of properties </param> /// <param name="values"> Output: correspondng list of values </param> private void GetPropertyValues( TypeInfo typeInfo, OperationKind opKind, Node input, bool ignoreMissingProperties, out List<md.EdmProperty> properties, out List<Node> values) { values = new List<Node>(); properties = new List<md.EdmProperty>(); foreach (var prop in GetProperties(typeInfo, opKind)) { var kv = GetPropertyValue(input, prop, ignoreMissingProperties); if (kv.Value != null) { properties.Add(kv.Key); values.Add(kv.Value); } } }
private IEnumerable<PropertyRef> GetPropertyRefs(TypeInfo typeInfo, OperationKind opKind) { PlanCompiler.Assert(opKind != OperationKind.All, "unexpected attempt to GetPropertyRefs(...,OperationKind.All)"); if (opKind == OperationKind.GetKeys) { return typeInfo.GetKeyPropertyRefs(); } else if (opKind == OperationKind.GetIdentity) { return typeInfo.GetIdentityPropertyRefs(); } else { return GetPropertyRefsForComparisonAndIsNull(typeInfo, opKind); } }
/// <summary> /// Create a node to represent a typeid constant for a prefix match. /// If the typeid value were "123X", then we would generate a constant /// like "123X%" /// </summary> /// <param name="typeInfo"> the current type </param> /// <returns> Node for the typeid constant </returns> private Node CreateTypeIdConstantForPrefixMatch(TypeInfo typeInfo) { var value = typeInfo.TypeId + PrefixMatchCharacter; var op = m_command.CreateInternalConstantOp(DefaultTypeIdType, value); return m_command.CreateNode(op); }
/// <summary> /// Builds up an accessor to the typeid property. If the type has no typeid /// property, then we simply create a constantOp with the corresponding /// typeid value for the type /// </summary> /// <param name="input"> the input expression </param> /// <param name="typeInfo"> the original type of the input expression </param> /// <returns> </returns> private Node BuildTypeIdAccessor(Node input, TypeInfo typeInfo) { Node result; if (typeInfo.HasTypeIdProperty) { result = BuildAccessorWithNulls(input, typeInfo.TypeIdProperty); } else { result = CreateTypeIdConstant(typeInfo); } return result; }
private Node CreateDisjunctiveTypeComparisonOp(TypeInfo typeInfo, Node typeIdProperty) { PlanCompiler.Assert(typeInfo.RootType.DiscriminatorMap != null, "should be used only for DiscriminatorMap type checks"); // collect all non-abstract types in the given hierarchy var types = typeInfo.GetTypeHierarchy().Where(t => !t.Type.EdmType.Abstract); // generate a disjunction Node current = null; foreach (var type in types) { var typeComparisonNode = CreateTypeEqualsOp(type, typeIdProperty); if (null == current) { current = typeComparisonNode; } else { current = m_command.CreateNode(m_command.CreateConditionalOp(OpType.Or), current, typeComparisonNode); } } if (null == current) { // only abstract types in this hierarchy... no values possible current = m_command.CreateNode(m_command.CreateFalseOp()); } return current; }
private static void RemoveNullSentinel(TypeInfo inputTypeInfo, List<md.EdmProperty> inputFields, List<Node> inputFieldValues) { PlanCompiler.Assert(inputFields[0] == inputTypeInfo.NullSentinelProperty, "InputField0 must be the null sentinel property"); inputFields.RemoveAt(0); inputFieldValues.RemoveAt(0); }
// <summary> // Assign a typeid to a non-root type. // Assigns typeids to a non-root type based on a dewey encoding scheme. // The typeid will be the typeId of the supertype suffixed by a // local identifier for the type. // </summary> // <param name="typeInfo"> the non-root type </param> // <param name="subtypeNum"> position in the subtype list </param> private void AssignTypeId(TypeInfo typeInfo, int subtypeNum) { typeInfo.TypeId = String.Format(CultureInfo.InvariantCulture, "{0}{1}X", typeInfo.SuperType.TypeId, subtypeNum); AssignTypeIdsToSubTypes(typeInfo); }
// <summary> // Assigns typeids to each subtype of the current type. // Assertion: the current type has already had a typeid assigned to it. // </summary> // <param name="typeInfo"> The current type </param> private void AssignTypeIdsToSubTypes(TypeInfo typeInfo) { // Now walk through all my subtypes, and assign their typeids var mySubTypeNum = 0; foreach (var subtype in typeInfo.ImmediateSubTypes) { AssignTypeId(subtype, mySubTypeNum); mySubTypeNum++; } }
// <summary> // Assign a typeid to a root type // </summary> private void AssignRootTypeId(TypeInfo typeInfo, string typeId) { typeInfo.TypeId = typeId; AssignTypeIdsToSubTypes(typeInfo); }
/// <summary> /// Create a column map for a ref type /// </summary> /// <param name="typeInfo"> Type information for the ref type </param> /// <param name="name"> Name of the column </param> /// <returns> Column map for the ref type </returns> private RefColumnMap CreateRefColumnMap(TypeInfo typeInfo, string name) { SimpleColumnMap entitySetIdColumnMap = null; if (typeInfo.HasEntitySetIdProperty) { entitySetIdColumnMap = CreateSimpleColumnMap( md.Helper.GetModelTypeUsage(typeInfo.EntitySetIdProperty), c_EntitySetIdColumnName); } // get the target entity type, var entityType = (md.EntityType)(TypeHelpers.GetEdmType<md.RefType>(typeInfo.Type).ElementType); // Iterate through the list of "key" properties var keyColList = new SimpleColumnMap[entityType.KeyMembers.Count]; for (var i = 0; i < keyColList.Length; ++i) { var property = entityType.KeyMembers[i]; keyColList[i] = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(property), property.Name); } // Create the entity identity var identity = CreateEntityIdentity(entityType, entitySetIdColumnMap, keyColList); var result = new RefColumnMap(typeInfo.Type, name, identity); return result; }
private RecordColumnMap CreateRecordColumnMap(TypeInfo typeInfo, string name) { PlanCompiler.Assert(typeInfo.Type.EdmType is md.RowType, "not RowType"); SimpleColumnMap nullSentinelColumnMap = null; if (typeInfo.HasNullSentinelProperty) { nullSentinelColumnMap = CreateSimpleColumnMap( md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName); } var properties = TypeHelpers.GetProperties(typeInfo.Type); var propertyColumnMapList = new ColumnMap[properties.Count]; for (var i = 0; i < propertyColumnMapList.Length; ++i) { md.EdmMember property = properties[i]; propertyColumnMapList[i] = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name); } var result = new RecordColumnMap(typeInfo.Type, name, propertyColumnMapList, nullSentinelColumnMap); return result; }
private SimplePolymorphicColumnMap CreatePolymorphicColumnMap(TypeInfo typeInfo, string name) { // if the typeInfo has a DiscriminatorMap, use TrailingSpaceComparer to ensure that lookups // against discriminator values that SQL Server has right-padded (e.g. nchar and char) are properly // interpreted var discriminatorMap = new Dictionary<object, TypedColumnMap>( typeInfo.RootType.DiscriminatorMap == null ? null : TrailingSpaceComparer.Instance); // abstract types may not have discriminator values, but may nonetheless be interesting var allMaps = new List<TypedColumnMap>(); // SQLBUDT #433011 -- Polymorphic types must construct column maps // that map to the entire type hierarchy, so we // need to use the RootType, not the current type. TypeInfo rootTypeInfo = typeInfo.RootType; // Get the type discriminant column first var typeIdColumnMap = CreateTypeIdColumnMap(rootTypeInfo.TypeIdProperty); // Prepare a place for the constructors to put the columns on the base // type, as they identify them. TypedColumnMap rootTypeColumnMap = null; // process complex/entity types appropriately // use the same name for the column if (md.TypeSemantics.IsComplexType(typeInfo.Type)) { rootTypeColumnMap = CreateComplexTypeColumnMap(rootTypeInfo, name, null, discriminatorMap, allMaps); } else { rootTypeColumnMap = CreateEntityColumnMap(rootTypeInfo, name, null, discriminatorMap, allMaps, true); } // Naturally, nothing is simple; we need to walk the rootTypeColumnMap hierarchy // and find the column map for the type that we are supposed to have as the base // type of this hierarchy. TypedColumnMap baseTypeColumnMap = null; foreach (var value in allMaps) { if (md.TypeSemantics.IsStructurallyEqual(value.Type, typeInfo.Type)) { baseTypeColumnMap = value; break; } } PlanCompiler.Assert(null != baseTypeColumnMap, "Didn't find requested type in polymorphic type hierarchy?"); // Create a polymorphic column map var result = new SimplePolymorphicColumnMap( typeInfo.Type, name, baseTypeColumnMap.Properties, typeIdColumnMap, discriminatorMap); return result; }
/// <summary> /// Build up the list of columnmaps for the relproperties. /// Assumption: rel-properties follow after ALL the regular properties of the /// types in the type hierarchy. /// For now, we're simply going to ignore the rel-property columnmaps - we're /// just going to use this function to "drain" the corresponding vars /// </summary> /// <param name="typeInfo"> typeinfo for the entity type </param> /// <param name="includeSupertypeRelProperties"> should we get rel-properties from our supertype instances </param> private void BuildRelPropertyColumnMaps(TypeInfo typeInfo, bool includeSupertypeRelProperties) { // // Get the appropriate set of rel-properties // IEnumerable<RelProperty> relProperties = null; if (includeSupertypeRelProperties) { relProperties = m_typeInfo.RelPropertyHelper.GetRelProperties(typeInfo.Type.EdmType as md.EntityTypeBase); } else { relProperties = m_typeInfo.RelPropertyHelper.GetDeclaredOnlyRelProperties(typeInfo.Type.EdmType as md.EntityTypeBase); } // // Create a column-map for each rel-properties // foreach (var property in relProperties) { var propertyColumnMap = CreateColumnMap(property.ToEnd.TypeUsage, property.ToString()); } // // Add all subtypes // foreach (var subTypeInfo in typeInfo.ImmediateSubTypes) { BuildRelPropertyColumnMaps(subTypeInfo, false); } }
/// <summary> /// Flattens a CaseOp - Specifically, if the CaseOp returns a structuredtype, /// then the CaseOp is broken up so that we build up a "flat" record constructor /// for that structured type, with each argument to the record constructor being /// a (scalar) CaseOp. For example: /// Case when b1 then e1 else e2 end /// gets translated into: /// RecordOp(case when b1 then e1.a else e2.a end, /// case when b1 then e1.b else e2.b end, /// ...) /// The property extraction is optimized by producing only those properties /// that have actually been requested. /// </summary> /// <param name="n"> Node corresponding to the CaseOp </param> /// <param name="typeInfo"> Information about the type </param> /// <param name="desiredProperties"> Set of properties desired </param> /// <returns> </returns> private Node FlattenCaseOp(Node n, TypeInfo typeInfo, PropertyRefList desiredProperties) { // Build up a type constructor - with only as many fields filled in // as are desired. var fieldTypes = new List<md.EdmProperty>(); var fieldValues = new List<Node>(); foreach (var pref in typeInfo.PropertyRefList) { // Is this property desired later? if (!desiredProperties.Contains(pref)) { continue; } var property = typeInfo.GetNewProperty(pref); // Build up an accessor for this property across each when/then clause var caseChildren = new List<Node>(); for (var i = 0; i < n.Children.Count - 1;) { var whenNode = Copy(n.Children[i]); caseChildren.Add(whenNode); i++; var propNode = BuildAccessorWithNulls(n.Children[i], property); caseChildren.Add(propNode); i++; } var elseNode = BuildAccessorWithNulls(n.Children[n.Children.Count - 1], property); caseChildren.Add(elseNode); var caseNode = m_command.CreateNode(m_command.CreateCaseOp(md.Helper.GetModelTypeUsage(property)), caseChildren); fieldTypes.Add(property); fieldValues.Add(caseNode); } var newRec = m_command.CreateNewRecordOp(typeInfo.FlattenedTypeUsage, fieldTypes); return m_command.CreateNode(newRec, fieldValues); }
// <summary> // A type needs a type-id property if it is an entity type or a complex tpe that // has subtypes. // Coming soon: relax the "need subtype" requirement (ie) any entity/complex type will // have a typeid // </summary> private static bool NeedsTypeIdProperty(TypeInfo typeInfo) { return typeInfo.ImmediateSubTypes.Count > 0 && !md.TypeSemantics.IsReferenceType(typeInfo.Type); }
/// <summary> /// Create a typeid-comparison operator - more specifically, create an /// operator that compares a typeid value with the typeid property of an /// input structured type. /// The comparison may be "exact" - in which case we're looking for the exact /// type; otherwise, we're looking for any possible subtypes. /// The "exact" variant is used by the IsOfOp (only); the other variant is /// used by IsOfOp and TreatOp /// </summary> /// <param name="input"> The input structured type expression </param> /// <param name="typeInfo"> Augmented type information for the type </param> /// <param name="isExact"> Exact comparison? </param> /// <returns> New comparison expression </returns> private Node CreateTypeComparisonOp(Node input, TypeInfo typeInfo, bool isExact) { var typeIdProperty = BuildTypeIdAccessor(input, typeInfo); Node newNode = null; if (isExact) { newNode = CreateTypeEqualsOp(typeInfo, typeIdProperty); } else { if (typeInfo.RootType.DiscriminatorMap != null) { // where there are explicit discriminator values, LIKE '0X%' pattern does not work... newNode = CreateDisjunctiveTypeComparisonOp(typeInfo, typeIdProperty); } else { var typeIdConstantNode = CreateTypeIdConstantForPrefixMatch(typeInfo); var likeOp = m_command.CreateLikeOp(); newNode = m_command.CreateNode(likeOp, typeIdProperty, typeIdConstantNode, CreateNullConstantNode(DefaultTypeIdType)); } } return newNode; }
// <summary> // A type needs a null-sentinel property if it is an row type that was projected // at the top level of the query; we capture that information in the preprocessor // and pass it in here. // </summary> private bool NeedsNullSentinelProperty(TypeInfo typeInfo) { return m_typesNeedingNullSentinel.Contains(typeInfo.Type.EdmType.Identity); }
/// <summary> /// Generates a node of the form typeIdProperty = typeInfo.TypeId /// </summary> /// <param name="typeInfo"> </param> /// <param name="typeIdProperty"> </param> /// <returns> type equality check </returns> private Node CreateTypeEqualsOp(TypeInfo typeInfo, Node typeIdProperty) { var typeIdConstantNode = CreateTypeIdConstant(typeInfo); var eqCompOp = m_command.CreateComparisonOp(OpType.EQ); var result = m_command.CreateNode(eqCompOp, typeIdProperty, typeIdConstantNode); return result; }
// <summary> // The type needs an entitysetidproperty, if it is either an entity type // or a reference type, AND we cannot determine that there is only entityset // in the query that could be producing instances of this entity // </summary> private bool NeedsEntitySetIdProperty(TypeInfo typeInfo) { md.EntityType entityType; var refType = typeInfo.Type.EdmType as md.RefType; if (refType != null) { entityType = refType.ElementType as md.EntityType; } else { entityType = typeInfo.Type.EdmType as md.EntityType; } var result = ((entityType != null) && (GetEntitySet(entityType) == null)); return result; }
/// <summary> /// Create a node to represent the exact value of the typeid constant /// </summary> /// <param name="typeInfo"> The current type </param> /// <returns> Node for the typeid constant </returns> private Node CreateTypeIdConstant(TypeInfo typeInfo) { var value = typeInfo.TypeId; md.TypeUsage typeIdType; if (typeInfo.RootType.DiscriminatorMap != null) { typeIdType = md.Helper.GetModelTypeUsage(typeInfo.RootType.DiscriminatorMap.DiscriminatorProperty); } else { typeIdType = DefaultTypeIdType; } var op = m_command.CreateInternalConstantOp(typeIdType, value); return m_command.CreateNode(op); }
// <summary> // Type Explosion - simply delegates to the root type // </summary> // <param name="typeInfo"> type info </param> private void ExplodeType(TypeInfo typeInfo) { ExplodeRootStructuredType(typeInfo.RootType); }
private IEnumerable<PropertyRef> GetPropertyRefsForComparisonAndIsNull(TypeInfo typeInfo, OperationKind opKind) { PlanCompiler.Assert( opKind == OperationKind.IsNull || opKind == OperationKind.Equality, "Unexpected opKind: " + opKind + "; Can only handle IsNull and Equality"); var currentType = typeInfo.Type; md.RowType recordType = null; if (TypeHelpers.TryGetEdmType(currentType, out recordType)) { if (opKind == OperationKind.IsNull && typeInfo.HasNullSentinelProperty) { yield return NullSentinelPropertyRef.Instance; } else { foreach (var m in recordType.Properties) { if (!TypeUtils.IsStructuredType(md.Helper.GetModelTypeUsage(m))) { yield return new SimplePropertyRef(m); } else { var nestedTypeInfo = m_typeInfo.GetTypeInfo(md.Helper.GetModelTypeUsage(m)); foreach (var p in GetPropertyRefs(nestedTypeInfo, opKind)) { var nestedPropertyRef = p.CreateNestedPropertyRef(m); yield return nestedPropertyRef; } } } } yield break; } md.EntityType entityType = null; if (TypeHelpers.TryGetEdmType(currentType, out entityType)) { if (opKind == OperationKind.Equality || (opKind == OperationKind.IsNull && !typeInfo.HasTypeIdProperty)) { foreach (var p in typeInfo.GetIdentityPropertyRefs()) { yield return p; } } else { yield return TypeIdPropertyRef.Instance; } yield break; } md.ComplexType complexType = null; if (TypeHelpers.TryGetEdmType(currentType, out complexType)) { PlanCompiler.Assert(opKind == OperationKind.IsNull, "complex types not equality-comparable"); PlanCompiler.Assert(typeInfo.HasNullSentinelProperty, "complex type with no null sentinel property: can't handle isNull"); yield return NullSentinelPropertyRef.Instance; yield break; } md.RefType refType = null; if (TypeHelpers.TryGetEdmType(currentType, out refType)) { foreach (var p in typeInfo.GetAllPropertyRefs()) { yield return p; } yield break; } PlanCompiler.Assert(false, "Unknown type"); }
// <summary> // Helper for ExplodeType. // Walks through each member introduced by the current type, and // adds it onto the "flat" record type being constructed. // We then walk through all subtypes of this type, and process those as // well. // Special handling for Refs: we only add the keys; there is no // need to handle subtypes (since they won't be introducing anything // different) // </summary> // <param name="typeInfo"> type in the type hierarchy </param> private void ExplodeRootStructuredTypeHelper(TypeInfo typeInfo) { var rootType = typeInfo.RootType; // Identify the members of this type. For Refs, use the key properties // of the target entity type. For all other types, simply use the type // members IEnumerable typeMembers = null; md.RefType refType; if (TypeHelpers.TryGetEdmType(typeInfo.Type, out refType)) { // // If this is not the root type, then don't bother adding the keys. // the root type has already done this // if (!typeInfo.IsRootType) { return; } typeMembers = refType.ElementType.KeyMembers; } else { typeMembers = TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type); } // Walk through all the members of the type foreach (md.EdmMember p in typeMembers) { var propertyType = ExplodeType(p.TypeUsage); // // If we can't find a TypeInfo for this property's type, then it must // be a scalar type or a collection type. In either case, we'll // build up a SimplePropertyRef // if (propertyType == null) { rootType.AddPropertyRef(new SimplePropertyRef(p)); } else { // // We're dealing with a structured type again. Create NestedPropertyRef // for each property of the nested type // foreach (var nestedPropInfo in propertyType.PropertyRefList) { rootType.AddPropertyRef(nestedPropInfo.CreateNestedPropertyRef(p)); } } } // // Process all subtypes now // foreach (var subTypeInfo in typeInfo.ImmediateSubTypes) { ExplodeRootStructuredTypeHelper(subTypeInfo); } }
/// <summary> /// Get a list of "desired" properties for each operationKind (specified by the opKind /// parameter). The OpKinds we support are /// * GetKeys /// Applies only to entity and ref types - gets the key properties (more specifically /// the flattened equivalents) /// * GetIdentity /// Applies only to entity and ref types - gets the entityset id property first, and then the /// the Key properties /// * All /// Gets all properties of the flattened type /// * Equality /// Scalar types - the entire instance /// Entity - the identity properties /// Ref - all properties (= identity properties) /// Complex/Collection - Not supported /// Record - recurse over each property /// * IsNull /// Scalar types - entire instance /// Entity - typeid property, if it exists; otherwise, the key properties /// ComplexType - typeid property /// Ref - all properties /// Collection - not supported /// Record - recurse over each property /// </summary> /// <param name="typeInfo"> Type information for the current op </param> /// <param name="opKind"> Current operation kind </param> /// <returns> List of desired properties </returns> private IEnumerable<md.EdmProperty> GetProperties(TypeInfo typeInfo, OperationKind opKind) { if (opKind == OperationKind.All) { foreach (var p in typeInfo.GetAllProperties()) { yield return p; } } else { foreach (var p in GetPropertyRefs(typeInfo, opKind)) { yield return typeInfo.GetNewProperty(p); } } }
// <summary> // Add the list of rel-properties for this type // </summary> // <param name="typeInfo"> the type to process </param> private void AddRelProperties(TypeInfo typeInfo) { var entityType = (md.EntityTypeBase)typeInfo.Type.EdmType; // // Walk through each rel-property defined for this specific type, // and add a corresponding property-ref // foreach (var p in m_relPropertyHelper.GetDeclaredOnlyRelProperties(entityType)) { var refType = p.ToEnd.TypeUsage.EdmType; var refTypeInfo = GetTypeInfo(p.ToEnd.TypeUsage); // // We're dealing with a structured type again - flatten this out // as well // ExplodeType(refTypeInfo); foreach (var nestedPropInfo in refTypeInfo.PropertyRefList) { typeInfo.RootType.AddPropertyRef(nestedPropInfo.CreateNestedPropertyRef(p)); } } // // Process all subtypes now // foreach (var subTypeInfo in typeInfo.ImmediateSubTypes) { AddRelProperties(subTypeInfo); } }
private Node CreateTVFProjection( Node unnestNode, List<Var> unnestOpTableColumns, TypeInfo unnestOpTableTypeInfo, out List<Var> newVars) { var originalRowType = unnestOpTableTypeInfo.Type.EdmType as md.RowType; PlanCompiler.Assert(originalRowType != null, "Unexpected TVF return type (must be row): " + unnestOpTableTypeInfo.Type); var convertToFlattenedTypeVars = new List<Var>(); var convertToFlattenedTypeVarDefs = new List<Node>(); var propRefs = unnestOpTableTypeInfo.PropertyRefList.ToArray(); var flattenedTypePropertyToPropertyRef = new Dictionary<md.EdmProperty, PropertyRef>(); foreach (var propRef in propRefs) { flattenedTypePropertyToPropertyRef.Add(unnestOpTableTypeInfo.GetNewProperty(propRef), propRef); } foreach (var flattenedTypeProperty in unnestOpTableTypeInfo.FlattenedType.Properties) { var propRef = flattenedTypePropertyToPropertyRef[flattenedTypeProperty]; Var var = null; var simplePropRef = propRef as SimplePropertyRef; if (simplePropRef != null) { // Find the corresponding column in the TVF output and build a var ref to it. var columnIndex = originalRowType.Members.IndexOf(simplePropRef.Property); PlanCompiler.Assert(columnIndex >= 0, "Can't find a column in the TVF result type"); convertToFlattenedTypeVarDefs.Add( m_command.CreateVarDefNode( m_command.CreateNode(m_command.CreateVarRefOp(unnestOpTableColumns[columnIndex])), out var)); } else { var nullSentinelPropRef = propRef as NullSentinelPropertyRef; if (nullSentinelPropRef != null) { // Null sentinel does not exist in the TVF output, so build a new null sentinel expression. convertToFlattenedTypeVarDefs.Add(m_command.CreateVarDefNode(CreateNullSentinelConstant(), out var)); } } PlanCompiler.Assert(var != null, "TVFs returning a collection of rows with non-primitive properties are not supported"); convertToFlattenedTypeVars.Add(var); } // Make sure unnestTableColumnVar is mapped to the ProjectOp outputs. newVars = convertToFlattenedTypeVars; // Create Project(Unnest(Func())) return m_command.CreateNode( m_command.CreateProjectOp(m_command.CreateVarVec(convertToFlattenedTypeVars)), unnestNode, m_command.CreateNode(m_command.CreateVarDefListOp(), convertToFlattenedTypeVarDefs)); }
/// <summary> /// Create a column map for a complextype column /// </summary> /// <param name="typeInfo"> Type information for the type </param> /// <param name="name"> column name </param> /// <param name="superTypeColumnMap"> Supertype info if any </param> /// <param name="discriminatorMap"> Dictionary of typeidvalue->column map </param> /// <param name="allMaps"> List of all maps </param> /// <returns> </returns> private ComplexTypeColumnMap CreateComplexTypeColumnMap( TypeInfo typeInfo, string name, ComplexTypeColumnMap superTypeColumnMap, Dictionary<object, TypedColumnMap> discriminatorMap, List<TypedColumnMap> allMaps) { var propertyColumnMapList = new List<ColumnMap>(); IEnumerable myProperties = null; SimpleColumnMap nullSentinelColumnMap = null; if (typeInfo.HasNullSentinelProperty) { nullSentinelColumnMap = CreateSimpleColumnMap( md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName); } // Copy over information from my supertype if it already exists if (superTypeColumnMap != null) { foreach (var c in superTypeColumnMap.Properties) { propertyColumnMapList.Add(c); } myProperties = TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type); } else { // need to get all members otherwise myProperties = TypeHelpers.GetAllStructuralMembers(typeInfo.Type); } // Now add on all of my "specific" properties foreach (md.EdmMember property in myProperties) { var propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name); propertyColumnMapList.Add(propertyColumnMap); } // Create a map for myself var columnMap = new ComplexTypeColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), nullSentinelColumnMap); // if a dictionary is supplied, add myself to the dictionary if (discriminatorMap != null) { discriminatorMap[typeInfo.TypeId] = columnMap; } if (allMaps != null) { allMaps.Add(columnMap); } // Finally walk through my subtypes - use the same column name foreach (var subTypeInfo in typeInfo.ImmediateSubTypes) { CreateComplexTypeColumnMap(subTypeInfo, name, columnMap, discriminatorMap, allMaps); } return columnMap; }