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;
        }