cc3c04e0ccfd2fa0f0102e5a801b4508cf6ce3f0
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / CacheForPrimitiveTypes.cs
1 //---------------------------------------------------------------------
2 // <copyright file="CacheForPrimitiveTypes.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 using System;
11 using System.Collections.Generic;
12 using System.Collections.ObjectModel;
13 using System.Data.EntityModel;
14 using System.Diagnostics;
15 using System.Text;
16 using System.Xml.Serialization;
17 using System.Xml;
18 using System.Xml.Schema;
19 using System.IO;
20 using System.Data.Common;
21 using System.Globalization;
22
23 namespace System.Data.Metadata.Edm
24 {
25     internal class CacheForPrimitiveTypes
26     {
27         #region Fields
28         // The primitive type kind is a list of enum which the EDM model 
29         // Every specific instantiation of the model should map their 
30         // primitive types to the edm primitive types.
31
32         // In this class, primitive type is to be cached
33
34         // Key for the cache: primitive type kind
35         // Value for the cache: List<PrimitiveType>.  A list is used because there an be multiple types mapping to the
36         // same primitive type kind.  For example, sqlserver has multiple string types.
37
38         private List<PrimitiveType>[] _primitiveTypeMap = new List<PrimitiveType>[EdmConstants.NumPrimitiveTypes];
39         #endregion
40
41         #region Methods
42         /// <summary>
43         /// Add the given primitive type to the primitive type cache
44         /// </summary>
45         /// <param name="type">The primitive type to add</param>
46         internal void Add(PrimitiveType type)
47         {
48             // Get to the list
49             List<PrimitiveType> primitiveTypes = EntityUtil.CheckArgumentOutOfRange(_primitiveTypeMap, (int)type.PrimitiveTypeKind, "primitiveTypeKind");
50
51             // If there isn't a list for the given model type, create one and add it
52             if (primitiveTypes == null)
53             {
54                 primitiveTypes = new List<PrimitiveType>();
55                 primitiveTypes.Add(type);
56                 _primitiveTypeMap[(int)type.PrimitiveTypeKind] = primitiveTypes;
57             }
58             else
59             {
60                 primitiveTypes.Add(type);
61             }
62         }
63
64         /// <summary>
65         /// Try and get the mapped type for the given primitiveTypeKind in the given dataspace
66         /// </summary>
67         /// <param name="primitiveTypeKind">The primitive type kind of the primitive type to retrieve</param>
68         /// <param name="facets">The facets to use in picking the primitive type</param>
69         /// <param name="type">The resulting type</param>
70         /// <returns>Whether a type was retrieved or not</returns>
71         internal bool TryGetType(PrimitiveTypeKind primitiveTypeKind, IEnumerable<Facet> facets, out PrimitiveType type)
72         {
73             type = null;
74
75             // Now, see if we have any types for this model type, if so, loop through to find the best matching one
76             List<PrimitiveType> primitiveTypes = EntityUtil.CheckArgumentOutOfRange(_primitiveTypeMap, (int)primitiveTypeKind, "primitiveTypeKind");
77             if ((null != primitiveTypes) && (0 < primitiveTypes.Count))
78             {
79                 if (primitiveTypes.Count == 1)
80                 {
81                     type = primitiveTypes[0];
82                     return true;
83                 }
84
85                 if (facets == null)
86                 {
87                     FacetDescription[] facetDescriptions = EdmProviderManifest.GetInitialFacetDescriptions(primitiveTypeKind);
88                     if (facetDescriptions == null)
89                     {
90                         type = primitiveTypes[0];
91                         return true;
92                     }
93
94                     Debug.Assert(facetDescriptions.Length > 0);
95                     facets = CacheForPrimitiveTypes.CreateInitialFacets(facetDescriptions);
96                 }
97
98                 Debug.Assert(type == null, "type must be null here");
99                 bool isMaxLengthSentinel = false;
100
101                 // Create a dictionary of facets for easy lookup
102                 foreach (Facet facet in facets)
103                 {
104                     if ((primitiveTypeKind == PrimitiveTypeKind.String ||
105                          primitiveTypeKind == PrimitiveTypeKind.Binary) &&
106                         facet.Value != null &&
107                         facet.Name == EdmProviderManifest.MaxLengthFacetName &&
108                         Helper.IsUnboundedFacetValue(facet))
109                     {
110                         // MaxLength has the sentinel value. So this facet need not be added.
111                         isMaxLengthSentinel = true;
112                         continue;
113                     }
114                 }
115
116                 int maxLength = 0;
117                 // Find a primitive type with the matching constraint
118                 foreach (PrimitiveType primitiveType in primitiveTypes)
119                 {
120                     if (isMaxLengthSentinel)
121                     {
122                         if (type == null)
123                         {
124                             type = primitiveType;
125                             maxLength = Helper.GetFacet(primitiveType.FacetDescriptions, EdmProviderManifest.MaxLengthFacetName).MaxValue.Value;
126                         }
127                         else
128                         {
129                             int newMaxLength = Helper.GetFacet(primitiveType.FacetDescriptions, EdmProviderManifest.MaxLengthFacetName).MaxValue.Value;
130                             if (newMaxLength > maxLength)
131                             {
132                                 type = primitiveType;
133                                 maxLength = newMaxLength;
134                             }
135                         }
136                     }
137                     else
138                     {
139                         type = primitiveType;
140                         break;
141                     }
142                 }
143
144                 Debug.Assert(type != null);
145                 return true;
146             }
147
148             return false;
149         }
150
151         private static Facet[] CreateInitialFacets(FacetDescription[] facetDescriptions)
152         {
153             Debug.Assert(facetDescriptions != null && facetDescriptions.Length > 0);
154
155             Facet[] facets = new Facet[facetDescriptions.Length];
156
157             for (int i = 0; i < facetDescriptions.Length; ++i)
158             {
159                 switch (facetDescriptions[i].FacetName)
160                 {
161                     case DbProviderManifest.MaxLengthFacetName:
162                         facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultMaxLengthFacetValue);
163                         break;
164
165                     case DbProviderManifest.UnicodeFacetName:
166                         facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultUnicodeFacetValue);
167                         break;
168
169                     case DbProviderManifest.FixedLengthFacetName:
170                         facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultFixedLengthFacetValue);
171                         break;
172
173                     case DbProviderManifest.PrecisionFacetName:
174                         facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultPrecisionFacetValue);
175                         break;
176
177                     case DbProviderManifest.ScaleFacetName:
178                         facets[i] = Facet.Create(facetDescriptions[i], TypeUsage.DefaultScaleFacetValue);
179                         break;
180
181                     default:
182                         Debug.Assert(false, "Unexpected facet");
183                         break;
184                 }
185             }
186
187             return facets;
188         }
189
190         /// <summary>
191         /// Get the list of the primitive types for the given dataspace
192         /// </summary>
193         /// <returns></returns>
194         internal System.Collections.ObjectModel.ReadOnlyCollection<PrimitiveType> GetTypes()
195         {
196             List<PrimitiveType> primitiveTypes = new List<PrimitiveType>();
197             foreach (List<PrimitiveType> types in _primitiveTypeMap)
198             {
199                 if (null != types)
200                 {
201                     primitiveTypes.AddRange(types);
202                 }
203             }
204             return primitiveTypes.AsReadOnly();
205         }
206         #endregion
207     }
208 }