数据库
首页 > 数据库> > c# – 基于.net的SQL CLR函数ComputeHash不与Cyrrilic一起使用

c# – 基于.net的SQL CLR函数ComputeHash不与Cyrrilic一起使用

作者:互联网

我编写了以下SQL CLR函数,以便散列大于8000字节的字符串值(T-SQL内置HASHBYTES函数的输入值的限制):

[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
public static SqlBinary HashBytes(SqlString algorithm, SqlString value)
{
    HashAlgorithm algorithmType = HashAlgorithm.Create(algorithm.Value);

    if (algorithmType == null || value.IsNull)
    {
        return new SqlBinary();
    }
    else
    {
        byte[] bytes = Encoding.UTF8.GetBytes(value.Value);
        return new SqlBinary(algorithmType.ComputeHash(bytes));
    }
}

它适用于拉丁字符串.例如,以下哈希值是相同的:

SELECT dbo.fn_Utils_GetHashBytes ('MD5', 'test'); -- 0x098F6BCD4621D373CADE4E832627B4F6
SELECT HASHBYTES ('MD5', 'test');                 -- 0x098F6BCD4621D373CADE4E832627B4F6

问题是它不适用于西里尔字符串.例如:

SELECT dbo.fn_Utils_GetHashBytes ('MD5 ', N'даровете на влъхвите') -- NULL
SELECT HashBytes ('MD5 ',N'даровете на влъхвите') -- 0x838B1B625A6074B2BE55CDB7FCEA2832

SELECT dbo.fn_Utils_GetHashBytes ('SHA256', N'даровете на влъхвите') -- 0xA1D65374A0B954F8291E00BC3DD9DF655D8A4A6BF127CFB15BBE794D2A098844
SELECT HashBytes ('SHA2_256',N'даровете на влъхвите') -- 0x375F6993E0ECE1864336E565C8E14848F2A4BAFCF60BC0C8F5636101DD15B25A 

我为MD5获取NULL,但如果代码作为控制台应用程序执行,则代码返回值.谁能说出我做错了什么?

另外,我从here获得了功能,其中一条评论说:

Careful with CLR SP parameters being silently truncated to 8000 bytes
– I had to tag the parameter with [SqlFacet(MaxSize = -1)] otherwise bytes after the 8000th would simply be ignored!

但我测试了这个,它工作正常.例如,如果我生成一个8000字节字符串的散列和相同字符串的第二个散列加一个符号,我得到的散列是不同的.

DECLARE @A VARCHAR(MAX) = '8000 bytes string...'
DECLARE @B VARCHAR(MAX) = @A + '1'
SELECT LEN(@A), LEN(@B)

SELECT IIF(dbo.fn_Utils_GetHashBytes ('MD5', @A + '1') = dbo.fn_Utils_GetHashBytes ('MD5', @B), 1, 0) -- 0

我应该担心吗?

解决方法:

 Encoding.UTF8.GetBytes(...)

SQL Server没有UTF-8的概念.使用UCS-2(UTF-16)或ASCII.使用的编码必须与您传递给HASHBYTES的编码相匹配.您可以很容易地看到HASHBYTES将以不同的方式散列VARCHAR与NVARCHAR:

select HASHBYTES('MD5', 'Foo')  -- 0x1356C67D7AD1638D816BFB822DD2C25D
select HASHBYTES('MD5', N'Foo') -- 0xB25FF0AD90D09D395090E8A29FF4C63C

最好的方法是更改​​SQLCLR函数以接受字节,而不是字符串,并在调用者中处理转换为VARBINARY.

 SELECT dbo.fn_Utils_GetHashBytes ('MD5', CAST(N'даровете на влъхвите' AS VARBINARY(MAX));

仅供参考,SQL Server 2016已经解除了对HASHBYTES的8000字节限制:

For SQL Server 2014 and earlier, allowed input values are limited to 8000 bytes.

标签:c,net,tsql,hash,sqlclr
来源: https://codeday.me/bug/20190611/1220487.html