问题 将CONTEXT_INFO转换为varchar以及生成的长度


我正在尝试使用 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,如何将其修剪回原始长度以正确存储?

更多信息:


5280
2018-02-24 16:47


起源



答案:


分配时 CONTEXT_INFO 它以空字节填充 0x00 长度为128个字节并成为 0x5465737455736572000000...

您可以使用

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

7
2018-02-24 16:56



但是我必须将排序规则更改为SQL_Latin1_General_CP437_BIN。这是基于反复试验,但这并没有让我充满信心。如何澄清我应该使用哪种排序规则? - Brett Postin
@Poz - 你没有在你的问题中陈述SQL Server版本。如果以前到2008年了 100 整理将无法使用。 - Martin Smith
道歉。我正在运行2005,但它也需要适用于上面的所有版本。 - Brett Postin
@Poz - 我只是用它来做任何事情 BIN version是您当前的默认排序规则。 BTW:您的数据库当前的默认排序规则是什么?想知道这是不是为什么亚伦的答案不适合你? - Martin Smith
所以 Latin1_General_BIN 将是 BIN 那个版本。 - Martin Smith


答案:


分配时 CONTEXT_INFO 它以空字节填充 0x00 长度为128个字节并成为 0x5465737455736572000000...

您可以使用

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

7
2018-02-24 16:56



但是我必须将排序规则更改为SQL_Latin1_General_CP437_BIN。这是基于反复试验,但这并没有让我充满信心。如何澄清我应该使用哪种排序规则? - Brett Postin
@Poz - 你没有在你的问题中陈述SQL Server版本。如果以前到2008年了 100 整理将无法使用。 - Martin Smith
道歉。我正在运行2005,但它也需要适用于上面的所有版本。 - Brett Postin
@Poz - 我只是用它来做任何事情 BIN version是您当前的默认排序规则。 BTW:您的数据库当前的默认排序规则是什么?想知道这是不是为什么亚伦的答案不适合你? - Martin Smith
所以 Latin1_General_BIN 将是 BIN 那个版本。 - Martin Smith


它被填补 CHAR(0)。尝试:

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

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


3
2018-02-24 17:02



+1我在答案中使用了一个显式的强制转换和整理条款 因为这个问题 但它只出现了 varbinary(max) 无论如何。 - Martin Smith
这个解决方案对我不起作用,长度仍为50.由于SQL 2005也许? - Brett Postin
实际上我找到了两个 - 一个运行9.00.3042,另一个运行9.00.4211,它工作 - 两个长度显示8。 - Aaron Bertrand
我正在运行9.00.5000.00,排序为Latin1_General_CI_AS。我的脚本与我的问题中的相同,您的行直接添加在“set @temp_userCode”语句下。 - Brett Postin
尝试添加一个明确的 COLLATE。我用的时候 Latin1_General_CI_AS 显然它不起作用(我的测试数据库是 SQL_Latin1_General_CP1_CI_AS)。 - Aaron Bertrand


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

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

没有杂乱的整理考虑:-)


2
2017-09-26 11:03





替换将在SQL服务器的不同安装上随机失败 除非您指定排序规则

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

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

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

这种行为几乎在7年前提交给微软:

问: 尝试替换NUL角色时   使用replace(),这是有效的   value有一个SQL排序规则,但不是   Windows排序规则。

A: 这是由于0x0000的事实   是Windows中未定义的字符   排序规则。所有未定义的字符   在比较期间被忽略,排序,   和模式匹配。所以寻找   'a'+ char(0)正在寻找   'a',搜索char(0)是   相当于空字符串。

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

在SQL排序规则中,没有概念   未定义的字符。每个代码   为点赋予权重,这就是原因   我们没有看到问题。


0
2017-07-24 09:33