【问题标题】:Casting CONTEXT_INFO to varchar and the resulting length将 CONTEXT_INFO 转换为 varchar 和结果长度
【发布时间】:2012-02-24 16:47:00
【问题描述】:

我正在尝试使用 CONTEXT_INFO 将用户代码从存储过程传递到 DELETE 触发器以进行表审计。

一切正常,但我注意到审计表中保存的用户代码长度不正确。

以这个脚本为例……

declare @userCode varchar(50)
set @userCode = 'TestUser'

declare @binary_userCode varbinary(128)
set @binary_userCode = cast(@userCode as varbinary(128))
set CONTEXT_INFO @binary_userCode

declare @temp_userCode varchar(50)
set @temp_userCode = (select cast(CONTEXT_INFO() as varchar(50)))

--set @temp_userCode = rtrim(ltrim(@temp_userCode))

select @userCode, len(@userCode), @temp_userCode, len(@temp_userCode)

set CONTEXT_INFO 0x

结果:

len(@userCode) = 8

len(@temp_userCode) = 50

为什么@temp_userCode 变量返回长度为 50,如何将其修剪回原始长度以正确存储?

更多信息:

运行 SQL Server 2005,但是该解决方案需要在 2005 以后的所有版本中运行。

【问题讨论】:

    标签: sql-server sql-server-2005 varchar varbinary context-info


    【解决方案1】:

    当分配给CONTEXT_INFO 时,它会用空字节0x00 填充到长度为128 字节的0x5465737455736572000000...

    你可以使用

    REPLACE(CAST(CONTEXT_INFO() AS varchar(128)) COLLATE Latin1_General_100_BIN , 
            0x00, 
            '')
    

    【讨论】:

    • 这可行,但是我必须将排序规则更改为 SQL_Latin1_General_CP437_BIN。这是基于反复试验,但这并没有让我充满信心。如何澄清我应该使用哪种排序规则?
    • @Poz - 您没有在问题中说明 SQL Server 版本。如果在 2008 年之前,100 排序规则将不可用。
    • 道歉。我正在运行 2005,但是它也需要适用于高于该版本的所有版本。
    • @Poz - 我会使用您当前默认排序规则的 BIN 版本。顺便说一句:您的数据库当前的默认排序规则是什么?想知道这是否就是 Aaron 的答案对您不起作用的原因?
    • 所以Latin1_General_BIN 将是BIN 的版本。
    【解决方案2】:

    它用CHAR(0) 填充。试试:

    set @temp_userCode = REPLACE(@temp_userCode COLLATE Latin1_General_BIN, CHAR(0), '');
    

    编辑:添加了一个明确的COLLATE 子句,虽然现在我觉得我在偷马丁。)

    【讨论】:

    • +1 我在答案because of this issue 中使用了明确的强制转换和整理子句,但无论如何它只出现在varbinary(max)
    • 这个解决方案对我不起作用,长度仍然是50。也许是由于SQL 2005?
    • 实际上我发现了两个 - 一个运行 9.00.3042,另一个运行 9.00.4211,并且它工作 - 两个长度都显示 8。
    • 我正在运行 9.00.5000.00,使用排序规则 Latin1_General_CI_AS。我的脚本与我的问题相同,您的行直接添加在“set @temp_userCode”语句下。
    • 尝试添加明确的COLLATE。当我明确使用Latin1_General_CI_AS 时它不起作用(我的测试数据库是SQL_Latin1_General_CP1_CI_AS)。
    【解决方案3】:

    试试这个,它适用于 SQL Server 2005:

    select cast(substring(CONTEXT_INFO(), 1, charindex(0x00, CONTEXT_INFO())-1) as varchar(128));
    

    无需考虑凌乱的排序规则 :-)

    【讨论】:

      【解决方案4】:

      在不同安装的 SQL server unless you specify the collation 上替换会随机失败:

      REPLACE(CAST(CONTEXT_INFO() AS varchar(128)) COLLATE Latin1_General_100_BIN , 0x00, '')
      

      SQL Server 有两种不同的行为,具体取决于它的安装方式:

      • 使用 SQL 排序规则时替换成功。
      • 使用 Windows 排序规则时替换不成功。

      这种行为是在将近 7 年前提交给微软的:

      问:尝试替换 NUL 字符时 使用replace(),这个作品是 value 有一个 SQL 排序规则,但没有 Windows 排序规则。

      答:这是因为 0x0000 是 Windows 中的未定义字符 排序规则。所有未定义的字符 在比较、排序、 和模式匹配。所以寻找 'a' + char(0) 真的在寻找 'a',搜索 char(0) 是 相当于空字符串。

      未定义字符的处理方式 有点混乱,但这是 Windows 定义的排序方式, 和 SQL Server 符合 通用 Windows API。

      在 SQL 排序规则中,没有概念 未定义的字符。每个代码 点被分配了一个权重,这就是为什么 我们认为那里没有问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-26
        • 1970-01-01
        • 2013-04-07
        相关资源
        最近更新 更多