SQLCLR 程序集注册失败(类型加载失败)

SQLCLR assembly registration failed (Type load failed)

我正在尝试在 SqlServer 中注册 SQLCLR 程序集

CREATE ASSEMBLY [DatabaseCLR]
FROM 'T:\DatabaseCLR.dll'
WITH PERMISSION_SET = SAFE
GO

但在注册过程中我收到错误消息

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.

这与 this 问题中描述的相似。然而,情况有点不同。在我的程序集中,我不使用用户定义的类型。

如果我使用PERMISSION_SET = UNSAFE 程序集注册成功。不过,我似乎没有使用不安全的代码("Allow unsafe code" 项目属性中未选中复选框)(或者我这样做?)。

汇编代码(简体)为:

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;
        }
    }
}

该程序集提供了对二进制类型进行按位运算的函数。我使用 struct[StructLayout(LayoutKind.Explicit)] 属性将 byte[] 数组转换为 ulong[] 数组(以加快处理速度)。我猜 StructLayout 的使用会导致相关问题中的错误。但是它不在 UDT 上,我不知道在这种情况下如何修复它。

是否有机会使用 PERMISSION_SET = SAFE 注册程序集?


我将示例函数注册为

CREATE FUNCTION dbo.BinaryHasSetBits
(
    @data varbinary(8000)
)
RETURNS BIT
AS EXTERNAL NAME [DatabaseCLR].[DatabaseCLR.BinaryUtils].[HasSetBits]
GO

我使用的是

的 x64 版本

错误是由于使用 LayoutKind.Explicit

改成LayoutKind.Sequential

[StructLayout(LayoutKind.Sequential)]
internal struct ByteToUlongConverter
{
    ...
}

使注册程序集成为可能PERMISSION_SET = SAFE

但是在这种情况下使用 LayoutKind.Sequential 而不是 LayoutKind.Explicit 会破坏语义。

因此,PERMISSION_SET = SAFELayoutKind.Explicit,而不是两者。