Question

Is it possible for a SQL CLR User-Defined Function to return the data type varbinary(MAX)?

In the documentation it mentions:

"The input parameters and the type returned from a scalar-valued function can be any of the scalar data types supported by SQL Server, except rowversion, text, ntext, image, timestamp, table, or cursor." - they don't mention varbinary, but I'm not sure...

I have some byte-array data from the .NET side that I need to return to SQL Server from the CLR, and I'm trying to avoid having to do it with an output parameter from a stored procedure (this is how I have it working in test now).

Thanks!

Was it helpful?

Solution

If you define it as returning a SqlBytes data type, this should correctly map to varbinary(MAX) in SQL Server.

[SqlFunction]
public static SqlBytes Function1()
{
    return new SqlBytes(Encoding.UTF8.GetBytes("Hello world."));
}

Whilst you can also use the SqlBinary data type, if you deploy via Visual Studio, it will be mapped onto varbinary(8000) rather than varbinary(MAX).

OTHER TIPS

Technically there is no 8000 byte maximum in the interface from SQL Server to CLR code. It is mainly a difference of how the T-SQL wrapper Stored Proc or Function is defined. Meaning, if the T-SQL Proc or Function that calls the CLR code defines the RETURNS as VARBINARY(MAX), then it shall be VARBINARY(MAX), whether or not you specified SqlBytes or SqlBinary as the return type of the CLR code.

Both SqlBytes and SqlBinary can handle the 2 GB limit, BUT the difference is in how the CLR code accepts the data. SqlBinary (just like SqlString) takes the parameter value all at once while SqlBytes (just like SqlChars) provides a streaming interface so it might be more efficient for very large values.

Going back to the issue that you are seeing with the pre-defined SQL Function wrapper, that is was a matter of how Visual Studio (technically SSDT) auto-generatesd the T-SQL. The default for SqlBinary is was VARBINARY(8000) while the default for SqlBytes is was VARBINARY(MAX). In the same manner, the default for SqlString is was NVARCHAR(4000) while the default for SqlChars is was NVARCHAR(MAX). Those were the defaults when this question was asked. Starting in perhaps Visual Studio 2012, the default was changed to use MAX for all 4 of these datatypes. This is not necessarily a good thing since there is a definite performance hit for using the MAX types vs the non-MAX types. So, if you don't need more than 8000 bytes of VARBINARY or 4000 bytes of NVARCHAR, then you will want to override the default using one of the following methods:

  1. You can ALTER the Function or Proc definition after it is generated by Visual Studio, and in this case you can even change the datatypes (of either input parameters or return values) to be any size such as VARBINARY(100) or NVARCHAR(50).

  2. You can use the SqlFacet decorator to tell Visual Studio / SSDT to auto-generate the Function or Proc definitions with the size option that you prefer as opposed to the default. The following example shows specifying the size for both input parameters and the return value (note that -1 = MAX):

    [return: SqlFacet(MaxSize = -1)]  
    [Microsoft.SqlServer.Server.SqlFunction(Name = "FunctionName")]  
    public static SqlBinary FuncName([SqlFacet(MaxSize = 50)] SqlString InputParam)
    

Using either of these two methods you can make either SqlBinary or SqlBytes map to either VARBINARY(1 - 8000) or VARBINARY(MAX). Likewise, you can make either SqlString or SqlChars map to eithert NVARCHAR(1 - 4000) or NVARCHAR(MAX).

It appears that the answer is yes - you can use both varbinary(MAX) by returning "SqlBinary" or you can use SqlBytes as recommended above.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top