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;
        }
 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;
     }
 }
 /// <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)
 {
     object value = typeInfo.TypeId;
     md.TypeUsage typeIdType;
     if (typeInfo.RootType.DiscriminatorMap != null)
     {
         typeIdType = md.Helper.GetModelTypeUsage(typeInfo.RootType.DiscriminatorMap.DiscriminatorProperty);
     }
     else
     {
         typeIdType = DefaultTypeIdType;
     }
     InternalConstantOp op = m_command.CreateInternalConstantOp(typeIdType, value);
     return m_command.CreateNode(op);
 }
 /// <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
     int mySubTypeNum = 0;
     foreach (TypeInfo subtype in typeInfo.ImmediateSubTypes)
     {
         AssignTypeId(subtype, mySubTypeNum);
         mySubTypeNum++;
     }
 }
        /// <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;
        }
        /// <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 (RelProperty property in relProperties)
            {
                ColumnMap propertyColumnMap = CreateColumnMap(property.ToEnd.TypeUsage, property.ToString());
            }

            //
            // Add all subtypes
            //
            foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes)
            {
                BuildRelPropertyColumnMaps(subTypeInfo, false);
            }
        }
        /// <summary>
        /// Create a column map for a record type. Simply iterates through the
        /// list of fields, and produces a column map for each field
        /// </summary>
        /// <param name="typeInfo">Type information for the record type</param>
        /// <param name="name">column name</param>
        /// <returns></returns>
        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);
            }

            md.ReadOnlyMetadataCollection<md.EdmProperty> properties = TypeHelpers.GetProperties(typeInfo.Type);
            ColumnMap[] propertyColumnMapList = new ColumnMap[properties.Count];
            for (int i = 0; i < propertyColumnMapList.Length; ++i)
            {
                md.EdmMember property = properties[i];
                propertyColumnMapList[i] = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
            }

            RecordColumnMap result = new RecordColumnMap(typeInfo.Type, name, propertyColumnMapList, nullSentinelColumnMap);
            return result;
        }
        /// <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 (md.EdmProperty prop in GetProperties(typeInfo, opKind))
            {
                KeyValuePair<md.EdmProperty, Node> kv = GetPropertyValue(input, prop, ignoreMissingProperties);
                if (kv.Value != null)
                {
                    properties.Add(kv.Key);
                    values.Add(kv.Value);
                }
            }
        }
        /// <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)
        {
            List<ColumnMap> 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 (ColumnMap 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)
            {
                ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
                propertyColumnMapList.Add(propertyColumnMap);
            }

            // Create a map for myself
            ComplexTypeColumnMap 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 (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes)
            {
                CreateComplexTypeColumnMap(subTypeInfo, name, columnMap, discriminatorMap, allMaps);
            }

            return columnMap;
        }
 /// <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)
 {
     string value = typeInfo.TypeId + PrefixMatchCharacter;
     InternalConstantOp op = m_command.CreateInternalConstantOp(DefaultTypeIdType, value);
     return m_command.CreateNode(op);
 }
 /// <summary>
 /// Get the list of "desired" propertyrefs for the specified type and operation
 /// </summary>
 /// <param name="typeInfo"></param>
 /// <param name="opKind"></param>
 /// <returns></returns>
 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>
        /// 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)
        {
            RootTypeInfo 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<md.RefType>(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)
            {
                TypeInfo 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 (PropertyRef nestedPropInfo in propertyType.PropertyRefList)
                    {
                        rootType.AddPropertyRef(nestedPropInfo.CreateNestedPropertyRef(p));
                    }
                }
            }

            // 
            // Process all subtypes now
            //
            foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes)
            {
                ExplodeRootStructuredTypeHelper(subTypeInfo);
            }
        }
        /// <summary>
        /// Add the list of rel-properties for this type
        /// </summary>
        /// <param name="typeInfo">the type to process</param>
        private void AddRelProperties(TypeInfo typeInfo)
        {

            md.EntityTypeBase entityType = (md.EntityTypeBase)typeInfo.Type.EdmType;

            //
            // Walk through each rel-property defined for this specific type, 
            // and add a corresponding property-ref
            //
            foreach (RelProperty p in m_relPropertyHelper.GetDeclaredOnlyRelProperties(entityType))
            {
                md.EdmType refType = p.ToEnd.TypeUsage.EdmType;
                TypeInfo refTypeInfo = GetTypeInfo(p.ToEnd.TypeUsage);

                //
                // We're dealing with a structured type again - flatten this out
                // as well
                //
                ExplodeType(refTypeInfo);

                foreach (PropertyRef nestedPropInfo in refTypeInfo.PropertyRefList)
                {
                    typeInfo.RootType.AddPropertyRef(nestedPropInfo.CreateNestedPropertyRef(p));
                }
            }

            // 
            // Process all subtypes now
            //
            foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes)
            {
                AddRelProperties(subTypeInfo);
            }
        }
 /// <summary>
 /// Type Explosion - simply delegates to the root type
 /// </summary>
 /// <param name="typeInfo">type info</param>
 private void ExplodeType(TypeInfo typeInfo)
 {
     ExplodeRootStructuredType(typeInfo.RootType);
 }
 /// <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>
 /// <param name="typeInfo"></param>
 /// <returns></returns>
 private bool NeedsEntitySetIdProperty(TypeInfo typeInfo)
 {
     md.EntityType entityType;
     md.RefType refType = typeInfo.Type.EdmType as md.RefType;
     if (refType != null)
     {
         entityType = refType.ElementType as md.EntityType;
     }
     else
     {
         entityType = typeInfo.Type.EdmType as md.EntityType;
     }
     bool result = ((entityType != null) && (GetEntitySet(entityType) == null));
     return result;
 }
 /// <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>
 /// <param name="typeInfo"></param>
 /// <returns></returns>
 private bool NeedsNullSentinelProperty(TypeInfo typeInfo)
 {
     return m_typesNeedingNullSentinel.Contains(typeInfo.Type.EdmType.Identity);
 }
 /// <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>
 /// <param name="typeInfo"></param>
 /// <returns></returns>
 private bool NeedsTypeIdProperty(TypeInfo typeInfo)
 {
     return typeInfo.ImmediateSubTypes.Count > 0 && !md.TypeSemantics.IsReferenceType(typeInfo.Type);
 }
 /// <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>
        /// Identify the list of property refs for comparison and isnull semantics
        /// </summary>
        /// <param name="typeInfo"></param>
        /// <param name="opKind"></param>
        /// <returns></returns>
        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");

            md.TypeUsage currentType = typeInfo.Type;

            md.RowType recordType = null;
            if (TypeHelpers.TryGetEdmType<md.RowType>(currentType, out recordType))
            {
                if (opKind == OperationKind.IsNull && typeInfo.HasNullSentinelProperty)
                {
                    yield return NullSentinelPropertyRef.Instance;
                }
                else
                    foreach (md.EdmProperty m in recordType.Properties)
                    {
                        if (!TypeUtils.IsStructuredType(md.Helper.GetModelTypeUsage(m)))
                        {
                            yield return new SimplePropertyRef(m);
                        }
                        else
                        {
                            TypeInfo nestedTypeInfo = m_typeInfo.GetTypeInfo(md.Helper.GetModelTypeUsage(m));
                            foreach (PropertyRef p in GetPropertyRefs(nestedTypeInfo, opKind))
                            {
                                PropertyRef nestedPropertyRef = p.CreateNestedPropertyRef(m);
                                yield return nestedPropertyRef;
                            }
                        }
                    }
                yield break;
            }

            md.EntityType entityType = null;
            if (TypeHelpers.TryGetEdmType<md.EntityType>(currentType, out entityType))
            {
                if (opKind == OperationKind.Equality ||
                    (opKind == OperationKind.IsNull && !typeInfo.HasTypeIdProperty))
                {
                    foreach (PropertyRef p in typeInfo.GetIdentityPropertyRefs())
                    {
                        yield return p;
                    }
                }
                else
                {
                    yield return TypeIdPropertyRef.Instance;
                }
                yield break;
            }

            md.ComplexType complexType = null;
            if (TypeHelpers.TryGetEdmType<md.ComplexType>(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<md.RefType>(currentType, out refType))
            {
                foreach (PropertyRef p in typeInfo.GetAllPropertyRefs())
                {
                    yield return p;
                }
                yield break;
            }

            PlanCompiler.Assert(false, "Unknown type");
        }
        /// <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="op">the CaseOp</param>
        /// <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(CaseOp op, Node n, TypeInfo typeInfo, PropertyRefList desiredProperties)
        {
            // Build up a type constructor - with only as many fields filled in 
            // as are desired. 
            List<md.EdmProperty> fieldTypes = new List<md.EdmProperty>();
            List<Node> fieldValues = new List<Node>();

            foreach (PropertyRef pref in typeInfo.PropertyRefList)
            {
                // Is this property desired later?
                if (!desiredProperties.Contains(pref))
                {
                    continue;
                }
                md.EdmProperty property = typeInfo.GetNewProperty(pref);

                // Build up an accessor for this property across each when/then clause
                List<Node> caseChildren = new List<Node>();
                for (int i = 0; i < n.Children.Count - 1; )
                {
                    Node whenNode = Copy(n.Children[i]);
                    caseChildren.Add(whenNode);
                    i++;

                    Node propNode = BuildAccessorWithNulls(n.Children[i], property);
                    caseChildren.Add(propNode);
                    i++;
                }
                Node elseNode = BuildAccessorWithNulls(n.Children[n.Children.Count - 1], property);
                caseChildren.Add(elseNode);

                Node caseNode = m_command.CreateNode(m_command.CreateCaseOp(md.Helper.GetModelTypeUsage(property)), caseChildren);

                fieldTypes.Add(property);
                fieldValues.Add(caseNode);
            }

            NewRecordOp newRec = m_command.CreateNewRecordOp(typeInfo.FlattenedTypeUsage, fieldTypes);
            return m_command.CreateNode(newRec, fieldValues);
        }
 /// <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 (md.EdmProperty p in typeInfo.GetAllProperties())
         {
             yield return p;
         }
     }
     else
     {
         foreach (PropertyRef p in GetPropertyRefs(typeInfo, opKind))
         {
             yield return typeInfo.GetNewProperty(p);
         }
     }
 }
 // We have to adjust for when we're supposed to remove null sentinels; 
 // columns (See SQLBUDT #553534 for an example).  Note that we shouldn't
 // have to add null sentinels here, since reference types won't be expecting
 // them (the fact that the key is null is good enough...)
 private static void RemoveNullSentinel(TypeInfo inputTypeInfo, List<md.EdmProperty> inputFields, List<Node> inputFieldValues, List<md.EdmProperty> outputFields)
 {
     PlanCompiler.Assert(inputFields[0] == inputTypeInfo.NullSentinelProperty, "InputField0 must be the null sentinel property");
     inputFields.RemoveAt(0);
     inputFieldValues.RemoveAt(0);
 }
        /// <summary>
        /// Project properties of <paramref name="unnestOpTableTypeInfo"/> that represents the flattened type of the <paramref name="unnestNode"/>.
        /// The <paramref name="unnestNode"/> contains a TVF call. 
        /// Return new node with ProjectOp and <paramref name="newVars"/> representing the projection outputs.
        /// </summary>
        private Node CreateTVFProjection(Node unnestNode, List<Var> unnestOpTableColumns, TypeInfo unnestOpTableTypeInfo, out List<Var> newVars)
        {
            md.RowType originalRowType = unnestOpTableTypeInfo.Type.EdmType as md.RowType;
            PlanCompiler.Assert(originalRowType != null, "Unexpected TVF return type (must be row): " + unnestOpTableTypeInfo.Type.ToString());

            List<Var> convertToFlattenedTypeVars = new List<Var>();
            List<Node> convertToFlattenedTypeVarDefs = new List<Node>();
            PropertyRef[] propRefs = unnestOpTableTypeInfo.PropertyRefList.ToArray();

            Dictionary<md.EdmProperty, PropertyRef> 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;
                SimplePropertyRef simplePropRef = propRef as SimplePropertyRef;
                if (simplePropRef != null)
                {
                    // Find the corresponding column in the TVF output and build a var ref to it.
                    int 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
                {
                    NullSentinelPropertyRef 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 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)
        {
            Node 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
                {
                    Node typeIdConstantNode = CreateTypeIdConstantForPrefixMatch(typeInfo);
                    LikeOp likeOp = m_command.CreateLikeOp();
                    newNode = m_command.CreateNode(likeOp, typeIdProperty, typeIdConstantNode, CreateNullConstantNode(DefaultTypeIdType));
                }
            }
            return newNode;
        }
        /// <summary>
        /// Create a column map for an entitytype column. 
        /// Currently, the key columns are not duplicated (ie) they point into the 
        /// same locations as in the properties list.
        /// Note: we also don't handle keys that are properties of nested fields
        /// </summary>
        /// <param name="typeInfo">Type information for the type</param>
        /// <param name="name">column name</param>
        /// <param name="superTypeColumnMap">supertype information if any</param>
        /// <param name="discriminatorMap">Dictionary of typeid->column map information</param>
        /// <param name="allMaps">List of all column maps (including those without typeid)</param>
        /// <param name="handleRelProperties">should we handle rel-properties?</param>
        /// <returns></returns>
        private EntityColumnMap CreateEntityColumnMap(TypeInfo typeInfo, string name, EntityColumnMap superTypeColumnMap,
            Dictionary<object, TypedColumnMap> discriminatorMap, List<TypedColumnMap> allMaps, bool handleRelProperties)
        {
            EntityColumnMap columnMap = null;
            List<ColumnMap> propertyColumnMapList = new List<ColumnMap>();

            // Copy over information from my supertype if it already exists
            if (superTypeColumnMap != null)
            {
                // get supertype properties
                foreach (ColumnMap c in superTypeColumnMap.Properties)
                {
                    propertyColumnMapList.Add(c);
                }
                // Now add on all of my "specific" properties
                foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type))
                {
                    ColumnMap 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
                List<SimpleColumnMap> keyColumnMapList = new List<SimpleColumnMap>();
                // Create a dictionary to look up the key properties
                Dictionary<md.EdmProperty, ColumnMap> keyPropertyMap = new Dictionary<md.EdmProperty, ColumnMap>();

                foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type))
                {
                    ColumnMap 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))
                    {
                        md.EdmProperty 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 (md.EdmMember keyProperty in TypeHelpers.GetEdmType<md.EntityType>(typeInfo.Type).KeyMembers)
                {
                    md.EdmProperty edmKeyProperty = keyProperty as md.EdmProperty;
                    PlanCompiler.Assert(edmKeyProperty != null, "EntityType key member is not property?");
                    SimpleColumnMap keyColumnMap = keyPropertyMap[edmKeyProperty] as SimpleColumnMap;
                    PlanCompiler.Assert(keyColumnMap != null, "keyColumnMap is null");
                    keyColumnMapList.Add(keyColumnMap);
                }

                //
                // Create the entity identity. 
                //
                EntityIdentity 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 (TypeInfo 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>
        /// Create a filter matching all types in the given hierarchy (typeIdProperty IN typeInfo.Hierarchy) e.g.:
        /// 
        ///     typeIdProperty = 'Base' OR typeIdProperty = 'Derived1' ...
        ///     
        /// This is called only for types using DiscriminatorMap (explicit discriminator values)
        /// </summary>
        /// <param name="typeInfo"></param>
        /// <param name="typeIdProperty"></param>
        /// <returns>type hierarchy check</returns>
        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
            IEnumerable<TypeInfo> types = typeInfo.GetTypeHierarchy().Where(t => !t.Type.EdmType.Abstract);

            // generate a disjunction
            Node current = null;
            foreach (TypeInfo type in types)
            {
                Node 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;
        }
        /// <summary>
        /// Creates a column map for a polymorphic type. This method first
        /// creates column maps for each type that is a subtype of the input type,
        /// and then creates a dictionary of typeid value -> column
        /// Finally, a PolymorphicColumnMap is created with these pieces of information
        /// </summary>
        /// <param name="typeInfo">Info about the type</param>
        /// <param name="name">column name</param>
        /// <returns></returns>
        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
            Dictionary<object, TypedColumnMap> discriminatorMap = new Dictionary<object, TypedColumnMap>(
                typeInfo.RootType.DiscriminatorMap == null ? null : TrailingSpaceComparer.Instance);
            // abstract types may not have discriminator values, but may nonetheless be interesting
            List<TypedColumnMap> 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
            SimpleColumnMap 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 (TypedColumnMap 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
            SimplePolymorphicColumnMap result = new SimplePolymorphicColumnMap(typeInfo.Type, name, baseTypeColumnMap.Properties, typeIdColumnMap, discriminatorMap);
            return result;
        }
 /// <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)
 {
     Node typeIdConstantNode = CreateTypeIdConstant(typeInfo);
     ComparisonOp eqCompOp = m_command.CreateComparisonOp(OpType.EQ);
     Node result = m_command.CreateNode(eqCompOp, typeIdProperty, typeIdConstantNode);
     return result;
 }
        /// <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, 
            md.EntityType entityType = (md.EntityType)(TypeHelpers.GetEdmType<md.RefType>(typeInfo.Type).ElementType);

            // Iterate through the list of "key" properties
            SimpleColumnMap[] keyColList = new SimpleColumnMap[entityType.KeyMembers.Count];
            for (int i = 0; i < keyColList.Length; ++i)
            {
                md.EdmMember property = entityType.KeyMembers[i];
                keyColList[i] = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
            }

            // Create the entity identity
            EntityIdentity identity = CreateEntityIdentity(entityType, entitySetIdColumnMap, keyColList);

            RefColumnMap result = new RefColumnMap(typeInfo.Type, name, identity);
            return result;
        }
 /// <summary>
 /// Assign a typeid to a root type
 /// </summary>
 /// <param name="typeInfo"></param>
 /// <param name="typeId"></param>
 private void AssignRootTypeId(TypeInfo typeInfo, string typeId)
 {
     typeInfo.TypeId = typeId;
     AssignTypeIdsToSubTypes(typeInfo);
 }