I'm trying to register SQLCLR assembly in SqlServer
CREATE ASSEMBLY [DatabaseCLR]
FROM 'T:\DatabaseCLR.dll'
WITH PERMISSION_SET = SAFE
GO
but during registration I get error message
Msg 6218, Level 16, State 2, Line 1 CREATE ASSEMBLY for assembly 'DatabaseCLR' failed because assembly 'DatabaseCLR' failed verification. Check if the referenced assemblies are up-to-date and trusted (for external_access or unsafe) to execute in the database. CLR Verifier error messages if any will follow this message
[ : DatabaseCLR.BinaryUtils::HasSetBits][mdToken=0x6000039] Type load failed.
[token 0x02000008] Type load failed.
which is similar to one described in this question. However the situation is a bit different. In my assembly I do not use User-Defined Types.
If I usePERMISSION_SET = UNSAFE
the assembly registers successfully. It doesn't seem that I use unsafe code though ("Allow unsafe code" checkbox is not checked in project properties) (or do I?).
The assembly code (simplified) is:
using System;
using System.Data.SqlTypes;
using System.Runtime.InteropServices;
using Microsoft.SqlServer.Server;
namespace DatabaseCLR
{
public class BinaryUtils
{
[SqlFunction(Name = "BinaryHasSetBits", IsDeterministic = true, IsPrecise = true)]
public static SqlBoolean HasSetBits(SqlBytes data)
{
if (data.IsNull)
return SqlBoolean.Null;
if (data.Storage != StorageState.Buffer)
throw new NotSupportedException(string.Format("Storage type {0} is not supported.", data.Storage));
long
len = data.Length,
ulen = len / sizeof(ulong),
tail = len % sizeof(ulong);
ByteToUlongConverter conv = new ByteToUlongConverter(data.Buffer);
for (long i = 0; i < ulen; i++)
if (conv.ulongs[i] != 0)
return SqlBoolean.True;
for (long i = len - tail; i < len; i++)
if (data.Buffer[i] != 0)
return SqlBoolean.True;
return SqlBoolean.False;
}
}
[StructLayout(LayoutKind.Explicit)]
internal struct ByteToUlongConverter
{
[FieldOffset(0)]
public byte[] bytes;
[FieldOffset(0)]
public ulong[] ulongs;
public ByteToUlongConverter(byte[] bytes)
{
this.ulongs = null;
this.bytes = bytes;
}
}
}
The assembly provides functions for bitwise operations on binary types. I'm using struct
with [StructLayout(LayoutKind.Explicit)]
attribute for casting byte[]
array to ulong[]
array (to speed up processing). I guess that use of StructLayout
causes error as in the related question. However it is not on UDT, and I do not see how I can fix it in this case.
Are there any chances to register assembly with PERMISSION_SET = SAFE
?
I do register my sample function as
CREATE FUNCTION dbo.BinaryHasSetBits
(
@data varbinary(8000)
)
RETURNS BIT
AS EXTERNAL NAME [DatabaseCLR].[DatabaseCLR.BinaryUtils].[HasSetBits]
GO
I'm using x64 editions of
The error is due to use of LayoutKind.Explicit
.
Changing it to LayoutKind.Sequential
[StructLayout(LayoutKind.Sequential)]
internal struct ByteToUlongConverter
{
...
}
makes possible registering assembly with PERMISSION_SET = SAFE
.
But using LayoutKind.Sequential
instead of LayoutKind.Explicit
breaks semantics in this case.
So, PERMISSION_SET = SAFE
or LayoutKind.Explicit
, not both.