1

I am trying to implement a basic SQL - VB CLR function which can check a list of values against a current value to test if the current value is included. (Mainly as a test of how to do CLR functions.) I have created the Dll, Loaded it to the database as assembly, create the function SQL and when I call it, I receive the following error. See below for the Error, SQL Function & Visual Basic Class. Note, 1 prior version of this function worked on the database a few times, but once I recieved this error, it gives me this same error every time now.

I have searched online and have found several posts which list the same problem, but none have a solution which works. The Compile has no errors, the assembly has no errors, database is trusted, CLR is enabled on the database. I just can't seem to figure out how to fix this issue. I have tried to implement null checking in the function, but the error seems to be occurring during the pass from SQL to the function itself, not within the function, so I thought it may be a datatype issue, but I am using SQL datatypes for both import and export... I do use vb data types within, but my null check should handle if there is any null data. Please Help!!!

Error Message:

Msg 6522, Level 16, State 2, Line 6
A .NET Framework error occurred during execution of user-defined routine or aggregate "fnCompareF": 
System.Data.SqlTypes.SqlNullValueException: Data is Null. This method or property cannot be called on Null values.
System.Data.SqlTypes.SqlNullValueException: 
   at System.Data.SqlTypes.SqlString.get_Value()
   at Common.JBM_CommonSQL.fnCompareF(SqlString strList, SqlString strCurrentValue)

SQL Function:

SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER FUNCTION dbo.fnCompareF (@List [nvarchar](4000), @CompareTo [nvarchar](4000))
RETURNS [bit] WITH EXECUTE AS CALLER, RETURNS NULL ON NULL INPUT
AS 
EXTERNAL NAME CommonSQL.[Common.JBM_CommonSQL].fnCompareF

VB 2013 Class:

Option Explicit On
Imports System.Collections
Imports System.Text
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server

Public Class JBM_CommonSQL

    <SqlFunction>
    Public Shared Function fnCompareF(strList As SqlString, strCurrentValue As SqlString) As SqlBoolean

        '----------------------------------------------------------------------------------------------------------------------------------------------------
        'THIS FUNCTION COMPARES A CURRENT VALUE TO A STRING, CONVERTS TO ARRAY
        'AND RETURNS TRUE IF THE ITEM IS FOUND IN THE ARRAY
        'strCompareList() = THIS IS EXPECTING ANY SINGLE DIMENSIONAL ARRAY (USUALLY STRING VALUES WHICH SHOULD BE COMPARED TO THE CURRENT VALUE
        '                   EVERY VALUE HERE IS COMPARED AGAINST THE strCurrentValue
        'strCurrentValue  = ANY STRING WHICH YOU WISH TO KNOW IS IN OR NOT IN THE ARRAY ABOVE
        '----------------------------------------------------------------------------------------------------------------------------------------------------
        Dim x As Long, strCompareList() As String, strDelim As String
If strList.IsNull Or strCurrentValue.IsNull Then fnCompareF = 0 : Exit Function
strDelim = fnFindDelim(strList)
        If strDelim = "" Then strDelim = ","
        strCompareList = Split(strList, strDelim)
        For x = LBound(strCompareList) To UBound(strCompareList)
            If UCase(strCompareList(x)) = UCase(CStr(strCurrentValue)) Then
                fnCompareF = 1
                Exit Function
            End If
        Next x
        fnCompareF = 0
    End Function

<SqlFunction> _
Public Shared Function fnFindDelim(strList As SqlString) As SqlString
    Dim strDelims() As String, x As Long, lngMax As Long, lngCount(2) As Long
    Dim strClean As String
    strDelims = Split("|#DEL#,#DEL#^#DEL#;", "#DEL#")
    For x = LBound(strDelims) To UBound(strDelims)
        lngCount(0) = Len(CType(strList, String))
        strClean = Replace(CType(strList, String), strDelims(x), "#DEL#")
        lngCount(1) = Len(strClean)
        lngCount(2) = (lngCount(1) - lngCount(0)) / 5
        If lngMax < lngCount(2) Then
            fnFindDelim = strDelims(x)
            lngMax = lngCount(2)
        End If

    Next x
End Function

End Class

SQL CODE CALLING THIS FUNCTION:

SELECT * FROM  dbo.WorkFlowMembers WHERE  DBO.fnCompareF(WorkFlowRoles, '1') = 1

Workflow members contains 2 columns, StaffID varchar(8), WorkflowRoles Varchar(50)

Workflow roles is a string usually containing a list of Role ID's IE( "1,2,3,4,5,6" )

I know the function parameters are for Nvarchar, however I have tried the same using cast( as nvarchar) and got the same error message. If I hardcode the Parameters DBO.fnCompareF('1,2,3,4,5', '1') = 1, The function works and returns a valid list.

I found the following question, and have tried the solution presented, but this did not work. SQL Server -- Handling null input in CLR User-Defined Function (UDF) with OnNullCall

Community
  • 1
  • 1

0 Answers0