1 //---------------------------------------------------------------------
2 // <copyright file="EdmFunction.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
10 using System.Collections.Generic;
11 using System.Diagnostics;
15 namespace System.Data.Metadata.Edm
18 /// Class for representing a function
20 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
21 public sealed class EdmFunction : EdmType
24 internal EdmFunction(string name, string namespaceName, DataSpace dataSpace, EdmFunctionPayload payload)
25 : base(name, namespaceName, dataSpace)
27 //---- name of the 'schema'
28 //---- this is used by the SQL Gen utility and update pipeline to support generation of the correct function name in the store
29 _schemaName = payload.Schema;
30 _fullName = this.NamespaceName + "." + this.Name;
32 FunctionParameter[] returnParameters = payload.ReturnParameters;
34 Debug.Assert(returnParameters.All((returnParameter) => returnParameter != null), "All return parameters must be non-null");
35 Debug.Assert(returnParameters.All((returnParameter) => returnParameter.Mode == ParameterMode.ReturnValue), "Return parameter in a function must have the ParameterMode equal to ReturnValue.");
37 _returnParameters = new ReadOnlyMetadataCollection<FunctionParameter>(
39 .Select((returnParameter) => SafeLink<EdmFunction>.BindChild<FunctionParameter>(this, FunctionParameter.DeclaringFunctionLinker, returnParameter))
42 if (payload.IsAggregate.HasValue) SetFunctionAttribute(ref _functionAttributes, FunctionAttributes.Aggregate, payload.IsAggregate.Value);
43 if (payload.IsBuiltIn.HasValue) SetFunctionAttribute(ref _functionAttributes, FunctionAttributes.BuiltIn, payload.IsBuiltIn.Value);
44 if (payload.IsNiladic.HasValue) SetFunctionAttribute(ref _functionAttributes, FunctionAttributes.NiladicFunction, payload.IsNiladic.Value);
45 if (payload.IsComposable.HasValue) SetFunctionAttribute(ref _functionAttributes, FunctionAttributes.IsComposable, payload.IsComposable.Value);
46 if (payload.IsFromProviderManifest.HasValue) SetFunctionAttribute(ref _functionAttributes, FunctionAttributes.IsFromProviderManifest, payload.IsFromProviderManifest.Value);
47 if (payload.IsCachedStoreFunction.HasValue) SetFunctionAttribute(ref _functionAttributes, FunctionAttributes.IsCachedStoreFunction, payload.IsCachedStoreFunction.Value);
48 if (payload.IsFunctionImport.HasValue) SetFunctionAttribute(ref _functionAttributes, FunctionAttributes.IsFunctionImport, payload.IsFunctionImport.Value);
50 if (payload.ParameterTypeSemantics.HasValue)
52 _parameterTypeSemantics = payload.ParameterTypeSemantics.Value;
55 if (payload.StoreFunctionName != null)
57 _storeFunctionNameAttribute = payload.StoreFunctionName;
60 if (payload.EntitySets != null)
62 Debug.Assert(_returnParameters.Count == payload.EntitySets.Length, "The number of entity sets should match the number of return parameters");
63 _entitySets = new ReadOnlyMetadataCollection<EntitySet>(payload.EntitySets);
67 var list = new List<EntitySet>();
68 if (_returnParameters.Count != 0)
70 Debug.Assert(_returnParameters.Count == 1, "If there was more than one result set payload.EntitySets should not have been null");
73 _entitySets = new ReadOnlyMetadataCollection<EntitySet>(list);
76 if (payload.CommandText != null)
78 _commandTextAttribute = payload.CommandText;
81 if (payload.Parameters != null)
83 // validate the parameters
84 foreach (FunctionParameter parameter in payload.Parameters)
86 if (parameter == null)
88 throw EntityUtil.CollectionParameterElementIsNull("parameters");
90 Debug.Assert(parameter.Mode != ParameterMode.ReturnValue, "No function parameter can have ParameterMode equal to ReturnValue.");
93 // Populate the parameters
94 _parameters = new SafeLinkCollection<EdmFunction, FunctionParameter>(this, FunctionParameter.DeclaringFunctionLinker, new MetadataCollection<FunctionParameter>(payload.Parameters));
98 _parameters = new ReadOnlyMetadataCollection<FunctionParameter>(new MetadataCollection<FunctionParameter>());
105 private readonly ReadOnlyMetadataCollection<FunctionParameter> _returnParameters;
106 private readonly ReadOnlyMetadataCollection<FunctionParameter> _parameters;
107 private readonly FunctionAttributes _functionAttributes = FunctionAttributes.Default;
108 private readonly string _storeFunctionNameAttribute;
109 private readonly ParameterTypeSemantics _parameterTypeSemantics;
110 private readonly string _commandTextAttribute;
111 private readonly string _schemaName;
112 private readonly ReadOnlyMetadataCollection<EntitySet> _entitySets;
113 private readonly string _fullName;
118 /// Returns the kind of the type
120 public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind.EdmFunction; } }
123 /// Returns the full name of this type, which is namespace + "." + name.
125 public override string FullName
134 /// Gets the collection of parameters
136 public ReadOnlyMetadataCollection<FunctionParameter> Parameters
145 /// Returns true if this is a C-space function and it has an eSQL body defined as DefiningExpression.
147 internal bool HasUserDefinedBody
151 return this.IsModelDefinedFunction && !String.IsNullOrEmpty(this.CommandTextAttribute);
156 /// For function imports, optionally indicates the entity set to which the result is bound.
157 /// If the function import has multiple result sets, returns the entity set to which the first result is bound
159 [MetadataProperty(BuiltInTypeKind.EntitySet, false)]
160 internal EntitySet EntitySet
164 return _entitySets.Count != 0 ? _entitySets[0] : null;
169 /// For function imports, indicates the entity sets to which the return parameters are bound.
170 /// The number of elements in the collection matches the number of return parameters.
171 /// A null element in the collection indicates that the corresponding are not bound to an entity set.
173 [MetadataProperty(BuiltInTypeKind.EntitySet, true)]
174 internal ReadOnlyMetadataCollection<EntitySet> EntitySets
183 /// Gets the return parameter of this function
185 [MetadataProperty(BuiltInTypeKind.FunctionParameter, false)]
186 public FunctionParameter ReturnParameter
190 return _returnParameters.FirstOrDefault();
195 /// Gets the return parameters of this function
197 [MetadataProperty(BuiltInTypeKind.FunctionParameter, true)]
198 public ReadOnlyMetadataCollection<FunctionParameter> ReturnParameters
202 return _returnParameters;
206 [MetadataProperty(PrimitiveTypeKind.String, false)]
207 internal string StoreFunctionNameAttribute
209 get { return _storeFunctionNameAttribute; }
212 [MetadataProperty(typeof(ParameterTypeSemantics), false)]
213 internal ParameterTypeSemantics ParameterTypeSemanticsAttribute
215 get { return _parameterTypeSemantics; }
218 // Function attribute parameters
219 [MetadataProperty(PrimitiveTypeKind.Boolean, false)]
220 internal bool AggregateAttribute
224 return GetFunctionAttribute(FunctionAttributes.Aggregate);
228 [MetadataProperty(PrimitiveTypeKind.Boolean, false)]
229 internal bool BuiltInAttribute
233 return GetFunctionAttribute(FunctionAttributes.BuiltIn);
237 [MetadataProperty(PrimitiveTypeKind.Boolean, false)]
238 internal bool IsFromProviderManifest
242 return GetFunctionAttribute(FunctionAttributes.IsFromProviderManifest);
246 [MetadataProperty(PrimitiveTypeKind.Boolean, false)]
247 internal bool NiladicFunctionAttribute
251 return GetFunctionAttribute(FunctionAttributes.NiladicFunction);
255 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Composable")]
256 [MetadataProperty(PrimitiveTypeKind.Boolean, false)]
257 public bool IsComposableAttribute
261 return GetFunctionAttribute(FunctionAttributes.IsComposable);
265 [MetadataProperty(PrimitiveTypeKind.String, false)]
266 public string CommandTextAttribute
270 return _commandTextAttribute;
274 internal bool IsCachedStoreFunction
278 return GetFunctionAttribute(FunctionAttributes.IsCachedStoreFunction);
282 internal bool IsModelDefinedFunction
286 return this.DataSpace == DataSpace.CSpace && !IsCachedStoreFunction && !IsFromProviderManifest && !IsFunctionImport;
290 internal bool IsFunctionImport
294 return GetFunctionAttribute(FunctionAttributes.IsFunctionImport);
298 [MetadataProperty(PrimitiveTypeKind.String, false)]
299 internal string Schema
310 /// Sets this item to be readonly, once this is set, the item will never be writable again.
312 internal override void SetReadOnly()
317 this.Parameters.Source.SetReadOnly();
318 foreach (FunctionParameter returnParameter in ReturnParameters)
320 returnParameter.SetReadOnly();
326 /// Builds function identity string in the form of "functionName (param1, param2, ... paramN)".
328 internal override void BuildIdentity(StringBuilder builder)
330 // If we've already cached the identity, simply append it
331 if (null != CacheIdentity)
333 builder.Append(CacheIdentity);
337 EdmFunction.BuildIdentity(
341 (param) => param.TypeUsage,
342 (param) => param.Mode);
346 /// Builds identity based on the functionName and parameter types. All parameters are assumed to be <see cref="ParameterMode.In"/>.
347 /// Returns string in the form of "functionName (param1, param2, ... paramN)".
349 internal static string BuildIdentity(string functionName, IEnumerable<TypeUsage> functionParameters)
351 StringBuilder identity = new StringBuilder();
358 (param) => ParameterMode.In);
360 return identity.ToString();
364 /// Builds identity based on the functionName and parameters metadata.
365 /// Returns string in the form of "functionName (param1, param2, ... paramN)".
367 internal static void BuildIdentity<TParameterMetadata>(StringBuilder builder,
369 IEnumerable<TParameterMetadata> functionParameters,
370 Func<TParameterMetadata, TypeUsage> getParameterTypeUsage,
371 Func<TParameterMetadata, ParameterMode> getParameterMode)
374 // Note: some callers depend on the format of the returned identity string.
377 // Start with the function name
378 builder.Append(functionName);
380 // Then add the string representing the list of parameters
383 foreach (TParameterMetadata parameter in functionParameters)
385 if (first) { first = false; }
386 else { builder.Append(","); }
387 builder.Append(Helper.ToString(getParameterMode(parameter)));
389 getParameterTypeUsage(parameter).BuildIdentity(builder);
394 private bool GetFunctionAttribute(FunctionAttributes attribute)
396 return attribute == (attribute & _functionAttributes);
399 private static void SetFunctionAttribute(ref FunctionAttributes field, FunctionAttributes attribute, bool isSet)
403 // make sure that attribute bits are set to 1
408 // make sure that attribute bits are set to 0
409 field ^= field & attribute;
417 private enum FunctionAttributes : byte
424 IsFromProviderManifest = 16,
425 IsCachedStoreFunction = 32,
426 IsFunctionImport = 64,
427 Default = IsComposable,
432 internal struct EdmFunctionPayload
435 public string NamespaceName;
436 public string Schema;
437 public string StoreFunctionName;
438 public string CommandText;
439 public EntitySet[] EntitySets;
440 public bool? IsAggregate;
441 public bool? IsBuiltIn;
442 public bool? IsNiladic;
443 public bool? IsComposable;
444 public bool? IsFromProviderManifest;
445 public bool? IsCachedStoreFunction;
446 public bool? IsFunctionImport;
447 public FunctionParameter[] ReturnParameters;
448 public ParameterTypeSemantics? ParameterTypeSemantics;
449 public FunctionParameter[] Parameters;
450 public DataSpace DataSpace;