2016-08-03 10:59:49 +00:00
//---------------------------------------------------------------------
// <copyright file="EdmFunction.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
2017-08-21 15:34:15 +00:00
// @owner Microsoft
// @backupOwner Microsoft
2016-08-03 10:59:49 +00:00
//---------------------------------------------------------------------
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Linq ;
using System.Text ;
namespace System.Data.Metadata.Edm
{
/// <summary>
/// Class for representing a function
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Edm")]
public sealed class EdmFunction : EdmType
{
#region Constructors
internal EdmFunction ( string name , string namespaceName , DataSpace dataSpace , EdmFunctionPayload payload )
: base ( name , namespaceName , dataSpace )
{
//---- name of the 'schema'
//---- this is used by the SQL Gen utility and update pipeline to support generation of the correct function name in the store
_schemaName = payload . Schema ;
_fullName = this . NamespaceName + "." + this . Name ;
FunctionParameter [ ] returnParameters = payload . ReturnParameters ;
Debug . Assert ( returnParameters . All ( ( returnParameter ) = > returnParameter ! = null ) , "All return parameters must be non-null" ) ;
Debug . Assert ( returnParameters . All ( ( returnParameter ) = > returnParameter . Mode = = ParameterMode . ReturnValue ) , "Return parameter in a function must have the ParameterMode equal to ReturnValue." ) ;
_returnParameters = new ReadOnlyMetadataCollection < FunctionParameter > (
returnParameters
. Select ( ( returnParameter ) = > SafeLink < EdmFunction > . BindChild < FunctionParameter > ( this , FunctionParameter . DeclaringFunctionLinker , returnParameter ) )
. ToList ( ) ) ;
if ( payload . IsAggregate . HasValue ) SetFunctionAttribute ( ref _functionAttributes , FunctionAttributes . Aggregate , payload . IsAggregate . Value ) ;
if ( payload . IsBuiltIn . HasValue ) SetFunctionAttribute ( ref _functionAttributes , FunctionAttributes . BuiltIn , payload . IsBuiltIn . Value ) ;
if ( payload . IsNiladic . HasValue ) SetFunctionAttribute ( ref _functionAttributes , FunctionAttributes . NiladicFunction , payload . IsNiladic . Value ) ;
if ( payload . IsComposable . HasValue ) SetFunctionAttribute ( ref _functionAttributes , FunctionAttributes . IsComposable , payload . IsComposable . Value ) ;
if ( payload . IsFromProviderManifest . HasValue ) SetFunctionAttribute ( ref _functionAttributes , FunctionAttributes . IsFromProviderManifest , payload . IsFromProviderManifest . Value ) ;
if ( payload . IsCachedStoreFunction . HasValue ) SetFunctionAttribute ( ref _functionAttributes , FunctionAttributes . IsCachedStoreFunction , payload . IsCachedStoreFunction . Value ) ;
if ( payload . IsFunctionImport . HasValue ) SetFunctionAttribute ( ref _functionAttributes , FunctionAttributes . IsFunctionImport , payload . IsFunctionImport . Value ) ;
if ( payload . ParameterTypeSemantics . HasValue )
{
_parameterTypeSemantics = payload . ParameterTypeSemantics . Value ;
}
if ( payload . StoreFunctionName ! = null )
{
_storeFunctionNameAttribute = payload . StoreFunctionName ;
}
if ( payload . EntitySets ! = null )
{
Debug . Assert ( _returnParameters . Count = = payload . EntitySets . Length , "The number of entity sets should match the number of return parameters" ) ;
_entitySets = new ReadOnlyMetadataCollection < EntitySet > ( payload . EntitySets ) ;
}
else
{
var list = new List < EntitySet > ( ) ;
if ( _returnParameters . Count ! = 0 )
{
Debug . Assert ( _returnParameters . Count = = 1 , "If there was more than one result set payload.EntitySets should not have been null" ) ;
list . Add ( null ) ;
}
_entitySets = new ReadOnlyMetadataCollection < EntitySet > ( list ) ;
}
if ( payload . CommandText ! = null )
{
_commandTextAttribute = payload . CommandText ;
}
if ( payload . Parameters ! = null )
{
// validate the parameters
foreach ( FunctionParameter parameter in payload . Parameters )
{
if ( parameter = = null )
{
throw EntityUtil . CollectionParameterElementIsNull ( "parameters" ) ;
}
Debug . Assert ( parameter . Mode ! = ParameterMode . ReturnValue , "No function parameter can have ParameterMode equal to ReturnValue." ) ;
}
// Populate the parameters
_parameters = new SafeLinkCollection < EdmFunction , FunctionParameter > ( this , FunctionParameter . DeclaringFunctionLinker , new MetadataCollection < FunctionParameter > ( payload . Parameters ) ) ;
}
else
{
_parameters = new ReadOnlyMetadataCollection < FunctionParameter > ( new MetadataCollection < FunctionParameter > ( ) ) ;
}
}
#endregion
#region Fields
private readonly ReadOnlyMetadataCollection < FunctionParameter > _returnParameters ;
private readonly ReadOnlyMetadataCollection < FunctionParameter > _parameters ;
private readonly FunctionAttributes _functionAttributes = FunctionAttributes . Default ;
private readonly string _storeFunctionNameAttribute ;
private readonly ParameterTypeSemantics _parameterTypeSemantics ;
private readonly string _commandTextAttribute ;
private readonly string _schemaName ;
private readonly ReadOnlyMetadataCollection < EntitySet > _entitySets ;
private readonly string _fullName ;
#endregion
#region Properties
/// <summary>
/// Returns the kind of the type
/// </summary>
public override BuiltInTypeKind BuiltInTypeKind { get { return BuiltInTypeKind . EdmFunction ; } }
/// <summary>
/// Returns the full name of this type, which is namespace + "." + name.
/// </summary>
public override string FullName
{
get
{
return _fullName ;
}
}
/// <summary>
/// Gets the collection of parameters
/// </summary>
public ReadOnlyMetadataCollection < FunctionParameter > Parameters
{
get
{
return _parameters ;
}
}
/// <summary>
/// Returns true if this is a C-space function and it has an eSQL body defined as DefiningExpression.
/// </summary>
internal bool HasUserDefinedBody
{
get
{
return this . IsModelDefinedFunction & & ! String . IsNullOrEmpty ( this . CommandTextAttribute ) ;
}
}
/// <summary>
/// For function imports, optionally indicates the entity set to which the result is bound.
/// If the function import has multiple result sets, returns the entity set to which the first result is bound
/// </summary>
[MetadataProperty(BuiltInTypeKind.EntitySet, false)]
internal EntitySet EntitySet
{
get
{
return _entitySets . Count ! = 0 ? _entitySets [ 0 ] : null ;
}
}
/// <summary>
/// For function imports, indicates the entity sets to which the return parameters are bound.
/// The number of elements in the collection matches the number of return parameters.
/// A null element in the collection indicates that the corresponding are not bound to an entity set.
/// </summary>
[MetadataProperty(BuiltInTypeKind.EntitySet, true)]
internal ReadOnlyMetadataCollection < EntitySet > EntitySets
{
get
{
return _entitySets ;
}
}
/// <summary>
/// Gets the return parameter of this function
/// </summary>
[MetadataProperty(BuiltInTypeKind.FunctionParameter, false)]
public FunctionParameter ReturnParameter
{
get
{
return _returnParameters . FirstOrDefault ( ) ;
}
}
/// <summary>
/// Gets the return parameters of this function
/// </summary>
[MetadataProperty(BuiltInTypeKind.FunctionParameter, true)]
public ReadOnlyMetadataCollection < FunctionParameter > ReturnParameters
{
get
{
return _returnParameters ;
}
}
[MetadataProperty(PrimitiveTypeKind.String, false)]
internal string StoreFunctionNameAttribute
{
get { return _storeFunctionNameAttribute ; }
}
[MetadataProperty(typeof(ParameterTypeSemantics), false)]
internal ParameterTypeSemantics ParameterTypeSemanticsAttribute
{
get { return _parameterTypeSemantics ; }
}
// Function attribute parameters
[MetadataProperty(PrimitiveTypeKind.Boolean, false)]
internal bool AggregateAttribute
{
get
{
return GetFunctionAttribute ( FunctionAttributes . Aggregate ) ;
}
}
[MetadataProperty(PrimitiveTypeKind.Boolean, false)]
internal bool BuiltInAttribute
{
get
{
return GetFunctionAttribute ( FunctionAttributes . BuiltIn ) ;
}
}
[MetadataProperty(PrimitiveTypeKind.Boolean, false)]
internal bool IsFromProviderManifest
{
get
{
return GetFunctionAttribute ( FunctionAttributes . IsFromProviderManifest ) ;
}
}
[MetadataProperty(PrimitiveTypeKind.Boolean, false)]
internal bool NiladicFunctionAttribute
{
get
{
return GetFunctionAttribute ( FunctionAttributes . NiladicFunction ) ;
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Composable")]
[MetadataProperty(PrimitiveTypeKind.Boolean, false)]
public bool IsComposableAttribute
{
get
{
return GetFunctionAttribute ( FunctionAttributes . IsComposable ) ;
}
}
[MetadataProperty(PrimitiveTypeKind.String, false)]
public string CommandTextAttribute
{
get
{
return _commandTextAttribute ;
}
}
internal bool IsCachedStoreFunction
{
get
{
return GetFunctionAttribute ( FunctionAttributes . IsCachedStoreFunction ) ;
}
}
internal bool IsModelDefinedFunction
{
get
{
return this . DataSpace = = DataSpace . CSpace & & ! IsCachedStoreFunction & & ! IsFromProviderManifest & & ! IsFunctionImport ;
}
}
internal bool IsFunctionImport
{
get
{
return GetFunctionAttribute ( FunctionAttributes . IsFunctionImport ) ;
}
}
[MetadataProperty(PrimitiveTypeKind.String, false)]
internal string Schema
{
get
{
return _schemaName ;
}
}
#endregion
#region Methods
/// <summary>
/// Sets this item to be readonly, once this is set, the item will never be writable again.
/// </summary>
internal override void SetReadOnly ( )
{
if ( ! IsReadOnly )
{
base . SetReadOnly ( ) ;
this . Parameters . Source . SetReadOnly ( ) ;
foreach ( FunctionParameter returnParameter in ReturnParameters )
{
returnParameter . SetReadOnly ( ) ;
}
}
}
/// <summary>
/// Builds function identity string in the form of "functionName (param1, param2, ... paramN)".
/// </summary>
internal override void BuildIdentity ( StringBuilder builder )
{
// If we've already cached the identity, simply append it
if ( null ! = CacheIdentity )
{
builder . Append ( CacheIdentity ) ;
return ;
}
EdmFunction . BuildIdentity (
builder ,
FullName ,
Parameters ,
( param ) = > param . TypeUsage ,
( param ) = > param . Mode ) ;
}
/// <summary>
/// Builds identity based on the functionName and parameter types. All parameters are assumed to be <see cref="ParameterMode.In"/>.
/// Returns string in the form of "functionName (param1, param2, ... paramN)".
/// </summary>
internal static string BuildIdentity ( string functionName , IEnumerable < TypeUsage > functionParameters )
{
StringBuilder identity = new StringBuilder ( ) ;
BuildIdentity (
identity ,
functionName ,
functionParameters ,
( param ) = > param ,
( param ) = > ParameterMode . In ) ;
return identity . ToString ( ) ;
}
/// <summary>
/// Builds identity based on the functionName and parameters metadata.
/// Returns string in the form of "functionName (param1, param2, ... paramN)".
/// </summary>
internal static void BuildIdentity < TParameterMetadata > ( StringBuilder builder ,
string functionName ,
IEnumerable < TParameterMetadata > functionParameters ,
Func < TParameterMetadata , TypeUsage > getParameterTypeUsage ,
Func < TParameterMetadata , ParameterMode > getParameterMode )
{
//
// Note: some callers depend on the format of the returned identity string.
//
// Start with the function name
builder . Append ( functionName ) ;
// Then add the string representing the list of parameters
builder . Append ( '(' ) ;
bool first = true ;
foreach ( TParameterMetadata parameter in functionParameters )
{
if ( first ) { first = false ; }
else { builder . Append ( "," ) ; }
builder . Append ( Helper . ToString ( getParameterMode ( parameter ) ) ) ;
builder . Append ( ' ' ) ;
getParameterTypeUsage ( parameter ) . BuildIdentity ( builder ) ;
}
builder . Append ( ')' ) ;
}
private bool GetFunctionAttribute ( FunctionAttributes attribute )
{
return attribute = = ( attribute & _functionAttributes ) ;
}
private static void SetFunctionAttribute ( ref FunctionAttributes field , FunctionAttributes attribute , bool isSet )
{
if ( isSet )
{
// make sure that attribute bits are set to 1
field | = attribute ;
}
else
{
// make sure that attribute bits are set to 0
field ^ = field & attribute ;
}
}
#endregion
#region Nested types
[Flags]
private enum FunctionAttributes : byte
{
None = 0 ,
Aggregate = 1 ,
BuiltIn = 2 ,
NiladicFunction = 4 ,
IsComposable = 8 ,
IsFromProviderManifest = 16 ,
IsCachedStoreFunction = 32 ,
IsFunctionImport = 64 ,
Default = IsComposable ,
}
#endregion
}
internal struct EdmFunctionPayload
{
public string Name ;
public string NamespaceName ;
public string Schema ;
public string StoreFunctionName ;
public string CommandText ;
public EntitySet [ ] EntitySets ;
public bool? IsAggregate ;
public bool? IsBuiltIn ;
public bool? IsNiladic ;
public bool? IsComposable ;
public bool? IsFromProviderManifest ;
public bool? IsCachedStoreFunction ;
public bool? IsFunctionImport ;
public FunctionParameter [ ] ReturnParameters ;
public ParameterTypeSemantics ? ParameterTypeSemantics ;
public FunctionParameter [ ] Parameters ;
public DataSpace DataSpace ;
}
}