Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / EntityModel / SchemaObjectModel / Parameter.cs
1 //---------------------------------------------------------------------
2 // <copyright file="Parameter.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       [....]
7 // @backupOwner [....]
8 //---------------------------------------------------------------------
9
10 namespace System.Data.EntityModel.SchemaObjectModel
11 {
12     using System;
13     using System.Collections.Generic;
14     using System.Data;
15     using System.Data.Entity;
16     using System.Data.Metadata.Edm;
17     using System.Diagnostics;
18     using System.Globalization;
19     using System.Text;
20     using System.Xml;
21     using Som = System.Data.EntityModel.SchemaObjectModel;
22
23     /// <summary>
24     /// Summary description for StructuredProperty.
25     /// </summary>
26     internal class Parameter : FacetEnabledSchemaElement
27     {
28         #region Instance Fields
29         private ParameterDirection _parameterDirection = ParameterDirection.Input;
30         private CollectionKind _collectionKind = CollectionKind.None;
31         private ModelFunctionTypeElement _typeSubElement = null;
32         private bool _isRefType = false;
33         #endregion
34
35         #region constructor
36         /// <summary>
37         /// 
38         /// </summary>
39         /// <param name="parentElement"></param>
40         internal Parameter(Function parentElement)
41             : base(parentElement)
42         {
43             _typeUsageBuilder = new TypeUsageBuilder(this);
44         }
45
46         #endregion
47
48         #region Public Properties
49
50         internal ParameterDirection ParameterDirection
51         {
52             get
53             {
54                 return _parameterDirection;
55             }
56         }
57
58         internal CollectionKind CollectionKind
59         {
60             get
61             {
62                 return _collectionKind;
63             }
64             set
65             {
66                 _collectionKind = value;
67             }
68         }
69
70         internal bool IsRefType
71         {
72             get { return _isRefType; }
73         }
74
75         internal override TypeUsage TypeUsage
76         {
77             get 
78             {
79                 if (_typeSubElement != null)
80                 {
81                     return _typeSubElement.GetTypeUsage();
82                 }
83                 else if (base.TypeUsage == null)
84                 {
85                     return null;
86                 }
87                 else if (CollectionKind != CollectionKind.None)
88                 {
89                     return TypeUsage.Create(new CollectionType(base.TypeUsage));
90                 }
91                 else
92                 {
93                     return base.TypeUsage;
94                 }
95             }
96         }
97
98         #endregion
99
100         new internal SchemaType Type
101         {
102             get
103             {
104                 return _type;
105             }
106         }
107
108
109         internal void WriteIdentity(StringBuilder builder)
110         {
111             builder.Append("Parameter(");
112             if (UnresolvedType != null && !UnresolvedType.Trim().Equals(String.Empty))
113             {
114                 if (_collectionKind != CollectionKind.None)
115                 {
116                     builder.Append("Collection(" + UnresolvedType + ")");
117                 }
118                 else if (_isRefType)
119                 {
120                     builder.Append("Ref(" + UnresolvedType + ")");
121                 }
122                 else
123                 {
124                     builder.Append(UnresolvedType);
125                 }
126             }
127             else if (_typeSubElement!=null)
128             {
129                 _typeSubElement.WriteIdentity(builder);
130             }
131             builder.Append(")");
132         }
133
134         internal override SchemaElement Clone(SchemaElement parentElement)
135         {
136             Parameter parameter = new Parameter((Function)parentElement);
137             parameter._collectionKind = _collectionKind;
138             parameter._parameterDirection = _parameterDirection;
139             parameter._type = _type;
140             parameter.Name = this.Name;
141             parameter._typeUsageBuilder = this._typeUsageBuilder;
142             return parameter;
143         }
144
145         internal bool ResolveNestedTypeNames(Converter.ConversionCache convertedItemCache, Dictionary<Som.SchemaElement, GlobalItem> newGlobalItems)
146         {
147             if (_typeSubElement == null)
148             {
149                 return false;
150             }
151             return _typeSubElement.ResolveNameAndSetTypeUsage(convertedItemCache, newGlobalItems);
152         }
153
154
155         protected override bool HandleAttribute(XmlReader reader)
156         {
157             if (base.HandleAttribute(reader))
158             {
159                 return true;
160             }
161             else if (CanHandleAttribute(reader, XmlConstants.TypeElement))
162             {
163                 HandleTypeAttribute(reader);
164                 return true;
165             }
166             else if (CanHandleAttribute(reader, XmlConstants.Mode))
167             {
168                 HandleModeAttribute(reader);
169                 return true;
170             }
171             else if (_typeUsageBuilder.HandleAttribute(reader))
172             {
173                 return true;
174             }
175
176             return false;
177         }
178
179         #region Private Methods
180
181         private void HandleTypeAttribute(XmlReader reader)
182         {
183             Debug.Assert(reader != null);
184             Debug.Assert(UnresolvedType == null);
185
186             string type;
187             if (!Utils.GetString(Schema, reader, out type))
188                 return;
189
190             TypeModifier typeModifier;
191
192             Function.RemoveTypeModifier(ref type, out typeModifier, out _isRefType);
193
194             switch (typeModifier)
195             {
196                 case TypeModifier.Array:
197                     CollectionKind = CollectionKind.Bag;
198                     break;
199                 default:
200                     Debug.Assert(typeModifier == TypeModifier.None, string.Format(CultureInfo.CurrentCulture, "Type is not valid for property {0}: {1}. The modifier for the type cannot be used in this context.", FQName, reader.Value));
201                     break;
202             }
203
204             if (!Utils.ValidateDottedName(Schema, reader, type))
205                 return;
206
207             UnresolvedType = type;
208         }
209
210         private void HandleModeAttribute(XmlReader reader)
211         {
212             Debug.Assert(reader != null);
213
214             string value = reader.Value;
215
216             if (String.IsNullOrEmpty(value))
217             {
218                 return;
219             }
220
221             value = value.Trim();
222
223             if (!String.IsNullOrEmpty(value))
224             {
225                 switch (value)
226                 {
227                     case XmlConstants.In:
228                         _parameterDirection = ParameterDirection.Input;
229                         break;
230                     case XmlConstants.Out:
231                         _parameterDirection = ParameterDirection.Output;
232                         if (this.ParentElement.IsComposable && this.ParentElement.IsFunctionImport) 
233                         {
234                             AddErrorBadParameterDirection(value, reader, System.Data.Entity.Strings.BadParameterDirectionForComposableFunctions);
235                         }
236                         break;
237                     case XmlConstants.InOut:
238                         _parameterDirection = ParameterDirection.InputOutput;
239                         if (this.ParentElement.IsComposable && this.ParentElement.IsFunctionImport)
240                         {
241                             AddErrorBadParameterDirection(value, reader, System.Data.Entity.Strings.BadParameterDirectionForComposableFunctions);
242                         }
243                         break;
244                     default:
245                         {                           
246                             AddErrorBadParameterDirection(value, reader, System.Data.Entity.Strings.BadParameterDirection);
247                         }
248                         break;
249                 }
250             }
251         }
252
253         private void AddErrorBadParameterDirection(string value, XmlReader reader, Func<object, object, object, object, string> errorFunc)
254         {
255             // don't try to identify the parameter by any of the attributes
256             // because we are still parsing attributes, and we don't know which ones
257             // have been parsed yet.
258             AddError(ErrorCode.BadParameterDirection, EdmSchemaErrorSeverity.Error, reader,
259                        errorFunc(
260                                 this.ParentElement.Parameters.Count, // indexed at 0 to be similar to the old exception
261                                 this.ParentElement.Name,
262                                 this.ParentElement.ParentElement.FQName,
263                                 value));
264         }
265
266         protected override bool HandleElement(XmlReader reader)
267         {
268             if (base.HandleElement(reader))
269             {
270                 return true;
271             }
272             else if (CanHandleElement(reader, XmlConstants.CollectionType))
273             {
274                 HandleCollectionTypeElement(reader);
275                 return true;
276             }
277             else if (CanHandleElement(reader, XmlConstants.ReferenceType))
278             {
279                 HandleReferenceTypeElement(reader);
280                 return true;
281             }
282             else if (CanHandleElement(reader, XmlConstants.TypeRef))
283             {
284                 HandleTypeRefElement(reader);
285                 return true;
286             }
287             else if (CanHandleElement(reader, XmlConstants.RowType))
288             {
289                 HandleRowTypeElement(reader);
290                 return true;
291             }
292             else if (Schema.DataModel == SchemaDataModelOption.EntityDataModel)
293             {
294                 if (CanHandleElement(reader, XmlConstants.ValueAnnotation))
295                 {
296                     // EF does not support this EDM 3.0 element, so ignore it.
297                     SkipElement(reader);
298                     return true;
299                 }
300                 else if (CanHandleElement(reader, XmlConstants.TypeAnnotation))
301                 {
302                     // EF does not support this EDM 3.0 element, so ignore it.
303                     SkipElement(reader);
304                     return true;
305                 }
306             }
307
308             return false;
309         }
310
311
312         protected void HandleCollectionTypeElement(XmlReader reader)
313         {
314             Debug.Assert(reader != null);
315
316             var subElement = new CollectionTypeElement(this);
317             subElement.Parse(reader);
318             _typeSubElement = subElement;
319         }
320
321         protected void HandleReferenceTypeElement(XmlReader reader)
322         {
323             Debug.Assert(reader != null);
324
325             var subElement = new ReferenceTypeElement(this);
326             subElement.Parse(reader);
327             _typeSubElement = subElement;
328         }
329
330         protected void HandleTypeRefElement(XmlReader reader)
331         {
332             Debug.Assert(reader != null);
333
334             var subElement = new TypeRefElement(this);
335             subElement.Parse(reader);
336             _typeSubElement = subElement;
337         }
338
339         protected void HandleRowTypeElement(XmlReader reader)
340         {
341             Debug.Assert(reader != null);
342
343             var subElement = new RowTypeElement(this);
344             subElement.Parse(reader);
345             _typeSubElement = subElement;
346         }
347
348         #endregion
349
350         internal override void ResolveTopLevelNames()
351         {
352             // If type was defined as an attribute: <ReturnType Type="int"/>
353             if (_unresolvedType != null)
354             {
355                 base.ResolveTopLevelNames();
356             }
357
358             // If type was defined as a subelement: <ReturnType><CollectionType>...</CollectionType></ReturnType>
359             if (_typeSubElement != null)
360             {
361                 _typeSubElement.ResolveTopLevelNames();
362             }
363         }
364
365         internal override void Validate()
366         {
367             base.Validate();
368
369             ValidationHelper.ValidateTypeDeclaration(this, _type, _typeSubElement);
370
371             if (Schema.DataModel != SchemaDataModelOption.EntityDataModel)
372             {
373                 Debug.Assert(Schema.DataModel == SchemaDataModelOption.ProviderDataModel ||
374                              Schema.DataModel == SchemaDataModelOption.ProviderManifestModel, "Unexpected data model");
375
376                 bool collectionAllowed = this.ParentElement.IsAggregate;
377
378                 // Only scalar parameters are allowed for functions in s-space.
379                 Debug.Assert(_typeSubElement == null, "Unexpected type subelement inside <Parameter> element.");
380                 if (_type != null && (_type is ScalarType == false || (!collectionAllowed && _collectionKind != CollectionKind.None)))
381                 {
382                     string typeName = "";
383                     if (_type != null)
384                     {
385                         typeName = Function.GetTypeNameForErrorMessage(_type, _collectionKind, _isRefType);
386                     }
387                     else if (_typeSubElement != null)
388                     {
389                         typeName = _typeSubElement.FQName;
390                     }
391                     if (Schema.DataModel == SchemaDataModelOption.ProviderManifestModel)
392                     {
393                         AddError(ErrorCode.FunctionWithNonEdmTypeNotSupported,
394                                  EdmSchemaErrorSeverity.Error,
395                                  this,
396                                  System.Data.Entity.Strings.FunctionWithNonEdmPrimitiveTypeNotSupported(typeName, this.ParentElement.FQName));
397                     }
398                     else
399                     {
400                         AddError(ErrorCode.FunctionWithNonPrimitiveTypeNotSupported,
401                                  EdmSchemaErrorSeverity.Error,
402                                  this,
403                                  System.Data.Entity.Strings.FunctionWithNonPrimitiveTypeNotSupported(typeName, this.ParentElement.FQName));
404                     }
405                     return;
406                 }
407             }
408
409             ValidationHelper.ValidateFacets(this, _type, _typeUsageBuilder);
410             
411             if (_isRefType)
412             {
413                 ValidationHelper.ValidateRefType(this, _type);
414             }
415             
416
417             if (_typeSubElement != null)
418             {
419                 _typeSubElement.Validate();
420             }
421         }
422     }
423 }