Showing posts with label sp_executesql. Show all posts
Showing posts with label sp_executesql. Show all posts

25 March 2025

🏭🗒️Microsoft Fabric: Security in Warehouse [Notes]

Disclaimer: This is work in progress intended to consolidate information from various sources for learning purposes. For the latest information please consult the documentation (see the links below)! 

Last updated: 25-Mar-2024

[Microsoft Fabric] Security in Warehouse
  • {def} suite of technologies aimed at safeguarding sensitive information in Fabric [1]
    • leverages SQL engine’s security features [1]
      • allows for security mechanism at the warehouse level [1]
      • ⇐ the warehouse and SQL analytics endpoint items also allow for the defining of native SQL security [4]
        • the permissions configured only apply to the queries executed against the respective surfaces [4]
      • the access to OneLake data is controlled separately through OneLake data access roles [4]
        • {recommendation} to ensure users with SQL specific permissions don't see data they don't have SQL access to, don't include those users in a OneLake data access role [4]
    • supports a range of data protection features that enable administrators to shield sensitive data from unauthorized access [1]
      • ⇐ across warehouses and SQL analytics endpoints without necessitating changes to applications [1]
    • {type} object-level security (OLS)
      • permissions governing DML operations [1]
        • applies to tables and views
        • ⇐ when denied, the user will be prevented from performing the respective operation
        • SELECT
          • allows users to view the data within the object [1]
        • INSERT
          • allows users to insert data in the object [1]
        • UPDATE
          • allows users to update data within the object [1]
        • DELETE
          • allows users to delete the data within the object [1]
      • permissions can be granted, revoked or denied on database objects [1]
        •  tables and views
        • GRANT
          • permission is granted to user or role [1]
        • DENY
          • permissions is denied to user or role [1]
        • REVOKE
          • permissions is revoked to user or role [1]
        • ALTER
          • grants the user the ability to change the definition of the object [1]
        • CONTROL
          • grants the user all rights to the object [1]
      • {principle} least privilege
        • users and applications should only be given the permissions needed in order for them to complete the task
    • {type} column-level security (CLS)
      • allows to restrict column access to sensitive data [1]
        • provides granular control over who can access specific pieces of data [1]
          •  enhances the overall security of the data warehouse [1]
      • steps
        • identify the sensitive columns [1]
        • define access roles [1]
        • assign roles to users [1]
        • implement access control [1]
          • restrict access to ta column based on user's role [1]
    • {type} row-level security (RLS)
      • provides granular control over access to rows in a table based on group membership or execution context [1]
        • using WHERE clause filters [1]
      • works by associating a function (aka security predicate) with a table [1]
        • defined to return true or false based on certain conditions [1]
          • ⇐ typically involving the values of one or more columns in the table [1]
          • when a user attempts to access data in the table, the security predicate function is invoked [1]
            • if the function returns true, the row is accessible to the user; otherwise, the row doesn't show up in the query results [1]
        • the predicate can be as simple/complex as required [1]
        • the process is transparent to the user and is enforced automatically by SQL Server
          • ⇐ ensures consistent application of security rules [1]
      • implemented in two main steps:
        • filter predicates 
          • an inline table-valued function that filters the results based on the predicate defined [1]
        • security policy
          • invokes an inline table-valued function to protect access to the rows in a table [1]
            • because access control is configured and applied at the warehouse level, application changes are minimal - if any [1]
            • users can directly have access to the tables and can query their own data [1]
      • {recommendation} create a separate schema for predicate functions, and security policies [1]
      • {recommendation} avoid type conversions in predicate functions [1]
      • {recommendation} to maximize performance, avoid using excessive table joins and recursion in predicate functions [1]
    • {type} dynamic data masking (DDM) 
      • allows to limits data exposure to nonprivileged users by obscuring sensitive data [1]
        • e.g. email addresses 
      • {benefit} enhance the security and manageability of the data [1]
      • {feature} real-time masking
        • when querying sensitive data, DDM applies dynamic masking to it in real time [1]
          • the actual data is never exposed to unauthorized users, thus enhancing the security of your data [1]
        • straightforward to implement [1]
        • doesn’t require complex coding, making it accessible for users of all skill levels [1]
        • {benefit} the data in the database isn’t changed when DDM is applied
          •   the actual data remains intact and secure, while nonprivileged users only see a masked version of the data [1]
      • {operation} define masking rule
        • set up at column level [1]
        • offers a suite of features [1]
          • comprehensive and partial masking capabilities [1]
          • supports several masking types
            • help prevent unauthorized viewing of sensitive data [1]
              • by enabling administrators to specify how much sensitive data to reveal [1]
                •   minimal effect on the application layer [1]
            • applied to query results, so the data in the database isn't changed 
              •   allows many applications to mask sensitive data without modifying existing queries  [1]
          • random masking function designed for numeric data [1]
        • {risk} unprivileged users with query permissions can infer the actual data since the data isn’t physically obfuscated [1]
      • {recommendation} DDM should be used as part of a comprehensive data security strategy [1]
        • should include
          • the proper management of object-level security with SQL granular permissions [1]
          • adherence to the principle of minimal required permissions [1]
    • {concept} Dynamic SQL 
      • allows T-SQL statements to be generated within a stored procedure or a query itself [1]
        • executed via sp_executesql stored procedure
      • {risk} SQL injection attacks
        • use  QUOTENAME to sanitize inputs [1]
  • write access to a warehouse or SQL analytics endpoint
    • {approach} granted through the Fabric workspace roles
      • the role automatically translates to a corresponding role in SQL that grants equivalent write access [4]
      • {recommendation} if a user needs write access to all warehouses and endpoints, assign the user to a workspace role [4]
        • use the Contributor role unless the user needs to assign other users to workspace roles [4]
      • {recommendation} grant direct access through SQL permissions if the user only needs to write to specific warehouses or endpoints [4]
    • {approach} grant read access to the SQL engine, and grant custom SQL permissions to write to some or all the data [4]
  • write access to a warehouse or SQL analytics endpoint
    • {approach} grant read access through the ReadData permission, granted as part of the Fabric workspace roles [4]
      •  ReadData permission maps the user to a SQL role that gives SELECT permissions on all tables in the warehouse or lakehouse
        • helpful if the user needs to see all or most of the data in the lakehouse or warehouse [4]
        • any SQL DENY permissions set on a particular lakehouse or warehouse still apply and limit access to tables [4]
        • row and column level security can be set on tables to restrict access at a granular level [4]
    • {approach} grant read access to the SQL engine, and grant custom SQL permissions to read to some or all the data [4]
    • if the user needs access only to a specific lakehouse or warehouse, the share feature provides access to only the shared item [4]
      • during the share, users can choose to give only Read permission or Read + ReadData 
        • granting Read permission allows the user to connect to the warehouse or SQL analytics endpoint but gives no table access [4]
        • granting users the ReadData permissions gives them full read access to all tables in the warehouse or SQL analytics endpoint
      • ⇐ additional SQL security can be configured to grant or deny access to specific tables [4]

    References:
    [1] Microsoft Learn (2024) Secure a Microsoft Fabric data warehouse [link]
    [2] Data Mozart (2025) Lock Up! Understanding Data Access Options in Microsoft Fabric, by Nikola Ilic [link]
    [3] Microsoft Learn (2024) Security in Microsoft Fabric [link]
    [4] Microsoft Learn (2024) Microsoft Fabric: How to secure a lakehouse for Data Warehousing teams [link]

    Resources:
    [R1] Microsoft Learn (2025) Fabric: What's new in Microsoft Fabric? [link]
    [R2] Microsoft Learn (2025) Fabric: Security for data warehousing in Microsoft Fabric [link]
    [R3] Microsoft Learn (2025) Fabric: Share your data and manage permissions [link]

    Acronyms:
    CLS - Column-Level Security
    DDM - Dynamic Data Masking
    DML - Data Manipulation Language 
    MF - Microsoft Fabric
    OLS - Object-Level Security
    RLS - Row-Level Security
    SQL - Structured Query Language

    15 January 2023

    💎🏭SQL Reloaded: Data Management Views for the Synapse serverless SQL pool (& Microsoft Fabric Warehouse)

    Unfortunately, the Dynamic Management Views (DMVs) for serverless SQL Server pools don't seem to be documented (or at least I haven't found them in the standard SQL Server documentation). I was thinking some weeks back how I could retrieve them easily as cursors aren't supported in serverless. In the end the old-fashioned loop got the job done (even if might not be the best way to do it):
     
    -- retrieving the data management views in use with the number of records they held
    DECLARE @view_name nvarchar(150)
    DECLARE @sql nvarchar(250)
    DECLARE @number_records bigint 
    DECLARE @number_views int, @iterator int
    
    DROP TABLE IF EXISTS dbo.#views;
    
    CREATE TABLE dbo.#views (
      ranking int NOT NULL
    , view_name nvarchar(150) NOT NULL
    )
    
    INSERT INTO #views
    SELECT row_number() OVER(ORDER BY object_id) ranking
    , concat(schema_name(schema_id),'.', name) view_name
    FROM sys.all_views obj
    WHERE obj.Type = 'V'
      AND obj.is_ms_shipped = 1
      --AND obj.name LIKE 'dm_exec_requests%'
    
    ORDER BY view_name
    SET @iterator = 1 SET @number_views = IsNull((SELECT count(*) FROM #views), 0) WHILE (@iterator <= @number_views) BEGIN SET @view_name = (SELECT view_name FROM #views WHERE ranking = @iterator) SET @sql = CONCAT(N'SELECT @NumberRecords = count(*) FROM ', @view_name) BEGIN TRY --get the number of records EXEC sp_executesql @Query = @sql , @params = N'@NumberRecords bigint OUTPUT' , @NumberRecords = @number_records OUTPUT IF IsNull(@number_records, 0)> 0 BEGIN SELECT @view_name, @number_records END END TRY BEGIN CATCH -- no action needed in case of error END CATCH; SET @iterator = @iterator + 1 END DROP TABLE IF EXISTS dbo.#views;

    As can be seen the code above retrieves the system views and dumps them in a temporary table, then loops through each record and for each record retrieves the number of records available with the sp_executesql. The call to the stored procedure is included in a TRY/CATCH block to surpress the error messages, considering that many standard SQL Server DMVs are not supported. The error messages follow the same pattern: 
    "Msg 15871, Level 16, State 9, Line 187
    DMV (Dynamic Management View) 'dm_resource_governor_resource_pool_volumes' is not supported." 
     On the instance I tested the code, from a total of 729 DMVs only 171 records were returned, though maybe there are some views not shown because the feature related to them was not yet configured:
     
    View nameDescription
    INFORMATION_SCHEMA.COLUMNSReturns one row for each column (*)
    INFORMATION_SCHEMA.PARAMETERSReturns one row for each parameter of a user-defined function or stored procedure (*)
    INFORMATION_SCHEMA.ROUTINE_COLUMNSReturns one row for each column returned by the table-valued functions (*)
    INFORMATION_SCHEMA.ROUTINESReturns one row for each stored procedure and function (*)
    INFORMATION_SCHEMA.SCHEMATAReturns one row for each schema in the current database
    INFORMATION_SCHEMA.TABLESReturns one row for each table or view in the current database (*)
    INFORMATION_SCHEMA.VIEW_COLUMN_USAGEReturns one row for each column in the current database that is used in a view definition
    INFORMATION_SCHEMA.VIEW_TABLE_USAGEReturns one row for each table in the current database that is used in a view
    INFORMATION_SCHEMA.VIEWSReturns one row for each view that can be accessed by the current user in the current database
    sys.all_columns
    sys.all_objects
    sys.all_parameters
    sys.all_sql_modules
    sys.all_views
    sys.allocation_units
    sys.assemblies
    sys.assembly_files
    sys.assembly_types
    sys.columns
    sys.configurations
    sys.credentials
    sys.data_spaces
    sys.database_automatic_tuning_options
    sys.database_automatic_tuning_options_internal
    sys.database_credentials
    sys.database_files
    sys.database_filestream_options
    sys.database_mirroring
    sys.database_mirroring_endpoints
    sys.database_permissions
    sys.database_principals
    sys.database_query_store_internal_state
    sys.database_query_store_options
    sys.database_recovery_status
    sys.database_resource_governor_workload_groups
    sys.database_role_members
    sys.database_scoped_configurations
    sys.database_scoped_credentials
    sys.databases
    sys.dm_exec_connections
    sys.dm_exec_query_stats
    sys.dm_exec_requestsReturns information about each request that is executing in SQL Server.
    sys.dm_exec_requests_historyReturns information about each request that executed in SQL Server; provided by Microsoft for troubleshooting.
    sys.dm_exec_sessions
    sys.dm_external_data_processed
    sys.dm_os_host_info
    sys.dm_request_phasesReturns information about each request phase performed in request's execution.
    sys.dm_request_phases_exec_task_statsReturns information about each task performed in request's execution.
    sys.dm_request_phases_task_group_statsReturns information aggregated at task group level about each task performed in request's execution.
    sys.endpoints
    sys.event_notification_event_types
    sys.extended_properties
    sys.external_data_sources
    sys.external_file_formats
    sys.external_language_files
    sys.external_languages
    sys.external_table_columns
    sys.external_tables
    sys.filegroups
    sys.fulltext_document_types
    sys.fulltext_languages
    sys.fulltext_system_stopwords
    sys.identity_columns
    sys.index_columns
    sys.indexes
    sys.internal_tables
    sys.key_encryptions
    sys.linked_logins
    sys.login_token
    sys.master_files
    sys.messages
    sys.objects
    sys.parameters
    sys.partitions
    sys.procedures
    sys.query_store_databases_health
    sys.query_store_global_health
    sys.resource_governor_configuration
    sys.resource_governor_external_resource_pools
    sys.resource_governor_resource_pools
    sys.resource_governor_workload_groups
    sys.routes
    sys.schemas
    sys.securable_classes
    sys.server_audit_specification_details
    sys.server_audit_specifications
    sys.server_audits
    sys.server_event_session_actions
    sys.server_event_session_events
    sys.server_event_session_fields
    sys.server_event_session_targets
    sys.server_event_sessions
    sys.server_memory_optimized_hybrid_buffer_pool_configuration
    sys.server_permissions
    sys.server_principals
    sys.server_role_members
    sys.servers
    sys.service_contract_message_usages
    sys.service_contract_usages
    sys.service_contracts
    sys.service_message_types
    sys.service_queue_usages
    sys.service_queues
    sys.services
    sys.spatial_reference_systems
    sys.sql_dependencies
    sys.sql_expression_dependencies
    sys.sql_logins
    sys.sql_modules
    sys.stats
    sys.stats_columns
    sys.symmetric_keys
    sys.sysaltfiles
    sys.syscacheobjects
    sys.syscharsets
    sys.syscolumns
    sys.syscomments
    sys.sysconfigures
    sys.syscurconfigs
    sys.sysdatabases
    sys.sysdepends
    sys.sysfilegroups
    sys.sysfiles
    sys.sysindexes
    sys.sysindexkeys
    sys.syslanguages
    sys.syslockinfo
    sys.syslogins
    sys.sysmembers
    sys.sysmessages
    sys.sysobjects
    sys.sysoledbusers
    sys.sysperfinfo
    sys.syspermissions
    sys.sysprocesses
    sys.sysprotects
    sys.sysservers
    sys.system_columns
    sys.system_components_surface_area_configuration
    sys.system_internals_allocation_units
    sys.system_internals_partition_columns
    sys.system_internals_partitions
    sys.system_objects
    sys.system_parameters
    sys.system_sql_modules
    sys.system_views
    sys.systypes
    sys.sysusers
    sys.tables
    sys.tcp_endpoints
    sys.time_zone_info
    sys.trace_categories
    sys.trace_columns
    sys.trace_event_bindings
    sys.trace_events
    sys.trace_subclass_values
    sys.trigger_event_types
    sys.type_assembly_usages
    sys.types
    sys.user_token
    sys.via_endpoints
    sys.views
    sys.xml_schema_attributes
    sys.xml_schema_collections
    sys.xml_schema_component_placements
    sys.xml_schema_components
    sys.xml_schema_facets
    sys.xml_schema_model_groups
    sys.xml_schema_namespaces
    sys.xml_schema_types
    sys.xml_schema_wildcards

    Notes:
    1) As can be seen, also the INFORMATION_SCHEMA views don't seem to be fully supprted.
    2) "(*)" in description marks the views that can be accessed by the current user in the current database.
    3) I removed the number of records as they are instance specific.
    4) The code should work also on a dedicated SQL Server pool.
    5) I hope to come back and showcase the usage of some of the most important views. 
    6) The script can be used for the Microsoft Fabric Warehouse, however each record will be shown in a different panel! One can use an additional temporary table to save the results or extend the views table and update the table with the result, like in the following script:

    -- retrieving the data management views in use with the number of records they held
    DECLARE @view_name nvarchar(150)
    DECLARE @sql nvarchar(250)
    DECLARE @number_records bigint 
    DECLARE @number_views int, @iterator int
    
    DROP TABLE IF EXISTS dbo.#views;
    
    CREATE TABLE dbo.#views (
      ranking int NOT NULL
    , view_name nvarchar(150) NOT NULL
    , record_count bigint NULL
    )
    
    INSERT INTO #views
    SELECT row_number() OVER(ORDER BY object_id) ranking
    , concat(schema_name(schema_id),'.', name) view_name
    , NULL record_count
    FROM sys.all_views obj
    WHERE obj.Type = 'V'
      AND obj.is_ms_shipped = 1
      --AND obj.name LIKE 'dm_exec_requests%'
    ORDER BY view_name
    
    SET @iterator = 1
    SET @number_views = IsNull((SELECT count(*) FROM #views), 0)
    
    WHILE (@iterator <= @number_views)
    BEGIN 
        SET @view_name = (SELECT view_name FROM #views WHERE ranking = @iterator)
        SET @sql = CONCAT(N'SELECT @NumberRecords = count(*) FROM ', @view_name)
    
    	BEGIN TRY
    		--get the number of records
    		EXEC sp_executesql @Query = @sql
    		, @params = N'@NumberRecords bigint OUTPUT'
    		, @NumberRecords = @number_records OUTPUT
    
    		IF IsNull(@number_records, 0)>= 0  
    		BEGIN
    		  UPDATE #views
                      SET record_count = @number_records
                      WHERE view_name = @view_name
    		END 
    	END TRY
    	BEGIN CATCH  
    	 -- no action needed in case of error
        END CATCH;
    
    	SET @iterator = @iterator + 1
    END
    
    SELECT *
    FROM dbo.#views;
    
    DROP TABLE IF EXISTS dbo.#views;

    Happy coding!

    11 July 2010

    💎SQL Reloaded: Evaluating Textual Expressions with CLR UDFs

    The developers having experience with scripting languages like VBScript or JavaScript are most probably used with Eval (VBScript/JavaScript) or Execute (VBScript) functions, functions that parse a string evaluating its content to an expression or evaluating a given set of instructions, allowing thus to create and execute code at runtime. In several occasions I needed similar functionality also in T-SQL, having to evaluate a formula stored in a text field or text variable. The latest situation of this type I could recall was when importing a set of BOM (Bill of Materials) data from Oracle into SQL Server. I had two problems then, one related to Oracle and the second to SQL Server. 

    As each level in the (Oracle) BOM has a Quantity which needs to be multiplied with the Quantities from the child levels in order to get the total Required Quantity for each level, I needed a method to aggregate the respective values. Unlike in SQL Server, in Oracle (as far I know) there is no built-in functionality for that, however SYS_CONNECT_BY_PATH function (see example) allows to built a string with the total quantities available in the BOM structure and is even possible to evaluate the resulted string using a function, though as I was not allowed to create a function in the production environment then, I had to solve the issue in SQL Server (2000) itself. The concatenated string of quantities at each BOM level was looking something like ‘1*1*2*4*1’ (here for the 5thBOM  level), so I needed a way to evaluate easily the respective product.

    In SQL Server the Cast and Convert functions allow to cast a string holding a numeric value to a numeric data type but their utility stops there.

    -- Cast/Convert (working) example 
    SELECT Cast('1' as int) * 25 
    , Convert(int, '1') * 10 
    
     
    Many years ago, I remember I “tried my luck” and attempted to run a similar script like the below one:

    -- Cast/Convert (not working) example 
    SELECT Cast('1*2' as int) * 25 
    , Convert(int, '1*2') * 10 
    
     
    No wonder that I got an error:
    Msg 245, Level 16, State 1, Line 1
    Conversion failed when converting the varchar value '1*2' to data type int.
    I attempted to find, again without luck, a built-in solution for my problem. For dynamic created scripts could be used, in general, the sp_executesql stored procedure:

    -- expression evaluation using sp_executesql (output: 6) DECLARE @retval int; 
    DECLARE @param int; 
    SET @param = 3 
    EXECUTE sp_executesql N'SELECT @retval = 1*2*@param', N'@param int, @retval int output', @param=@param, @retval = @retval output;  
    SELECT @retval 
    

    Unfortunately the sp_executesql can’t be used from UDFs, therefore the functionality can’t be used in queries involving a select from a given object. However, given its simplicity, the string could be regarded as a list of numbers delimited by “*” (multiplication) sign, a loop or starting with SQL Server 2005, a common table expression could solve the problem but it will work only for this type of multiplications, unless the expression is parsed using specific mathematical algorithms. Then I wrote a function similar with the below one:

    CREATE FUNCTION dbo.EvalProduct( 
    @ListValues varchar(max)) 
    RETURNS decimal(18,2) 
    /* 
    Purpose: evaluates the product of multiple numbers written as a text expression 
    Parameters: @ListValues varchar(max) - List of values to be multiplied 
    Sample call: SELECT dbo.EvalProduct('1*2*3*4') 
    SELECT dbo.EvalProduct('1.2*2.3*3.4') 
    SELECT dbo.EvalProduct('1.2') 
    SELECT dbo.EvalProduct('NULL') 
    */ AS 
    BEGIN 
    DECLARE @Index int 
    DECLARE @Product decimal(18,2) 
    SET @Index = CharIndex('*', @ListValues) 
    SET @Product = CASE 
         WHEN @Index&gt;1 OR (@Index = 0 AND IsNumeric(@ListValues) = 1) THEN 1 
         ELSE NULL 
    END  
    
    WHILE @Index &gt; 0  
    BEGIN 
        SET @Product = @Product * Cast(Left(@ListValues, @Index-1) as decimal(18,2)) 
    
        SET @ListValues = Right(@ListValues, Len(@ListValues)-@Index) 
        SET @Index = CharIndex('*', @ListValues) 
    END  
    
    IF IsNumeric(@ListValues)=1 
    SET @Product = @Product * Cast(@ListValues as decimal(18,2))  
    
    RETURN @Product 
    END 
    

    The function, even if handy, it has its limitations, first of all it works only with products of positive numeric values, and secondly there is no chance to use it for more complex expressions. Fortunately, starting with SQL Server 2005 there is an alternative.  In last post, Data Profiling Using CLR Functions I introduced ExecuteScalarToInt and ExecuteScalarToDecimal CLR functions which could be used to evaluate a text expression to an integer, respectively a decimal value, and thus they could be used also to solve the above problem:  

    -- CLR functions approach (Output: 120, respectively 236.48) 
    SELECT dbo.ExecuteScalarToInt('SELECT 1*2*3*4*5') IntExample 
    , dbo.ExecuteScalarToDecimal('SELECT 1.2*2.3*3.4*4.5*5.6') DecimalExample  
    

    The functions could be actually used with any type of expression that returns a numeric value, the expressions could include also built-in or user-defined functions:
     
    -- CLR with built-in mathematical functions (Output: 21.76)
    SELECT dbo.ExecuteScalarToDecimal('SELECT Pi()*SQRT(47.98)') 
    
    --CLR with UDF (Output: 9.38) 
    SELECT dbo.ExecuteScalarToDecimal('SELECT dbo.EvalProduct(''1.2*2.3*3.4'')') 
    

    This means that the two functions could be used for example in queries in which the formulas following to be executed are stored in tables or built dynamically. Let’s look at an example based on the values stored in a table:

    -- creating a simple table 
     CREATE TABLE dbo.TestTextExpressions ( 
    Expression varchar(max)) 
    
    --inserting the values 
    INSERT INTO dbo.TestTextExpressions 
    VALUES ('1*2*3*4') 
    , ('Pi()*SQRT(47.98)') 
    , ('Cos(10)') 
    , ('Year(GetDate())') 
    , ('Square(10.45)') 
    
    -- running the formulas 
    SELECT Expression 
    , dbo.ExecuteScalarToDecimal('SELECT ' + Expression) [Output]      
    FROM dbo.TestTextExpressions   
    


    CLR UDF - expression evaluation 
       
    Notes:
    1.    Instead of adding the SELECT in the parameter string, it could be created a CLR function (e.g. EvalToInt) that includes it already. Not sure how much benefit could be obtained from this, however I prefer to have generalized functionality rather then providing specific functions for each scenario.
    2.    Most probably there are also exceptions in which this approach can’t be used. As the two CLR functions don’t perform any validation, the usefulness of such functions depends also on the validity of the input. If the input is invalid, then an error will be thrown; on the other side, even if it’s possible to catch the error in the CLR functions itself, it could prove to be difficult to alter function’s behavior (for example returning a NULL value) without impacting the result.
    3.    In order to run UDFs from CLR UDFs, the SystemDataAccess:=SystemDataAccessKind.Read must be added in CLR functions definitions, otherwise the following error message will be thrown.
    This statement has attempted to access data whose access is restricted by the assembly
    PS:  It would be nice to receive some feedback on how the above functions helped you to solve a similar problem!

    Happy coding!
    Related Posts Plugin for WordPress, Blogger...

    About Me

    My photo
    Koeln, NRW, Germany
    IT Professional with more than 25 years experience in IT in the area of full life-cycle of Web/Desktop/Database Applications Development, Software Engineering, Consultancy, Data Management, Data Quality, Data Migrations, Reporting, ERP implementations & support, Team/Project/IT Management, etc.