SQL Server,CONTEXT_INFO()和varchar大小

时间:2016-01-22 01:15:56

标签: sql-server context-info

在表格users中,我有一个数据类型为username的列varchar(50)。该表没有记录。我为用户名插入了A的新记录。以下内容将返回我的期望:

SELECT username, LEN(username) 
FROM users 
WHERE id = 1 -- returns: A, 1

到目前为止一切顺利。

现在,我使用CONTEXT_INFO()

中的值从另一个表上的触发器更新表用户
set @context = cast('B' as varbinary(128))
set CONTEXT_INFO @context

update some_other_table 
set x = 'y' 
where id = 97

在我some_other_table的触发器中:

DECLARE @context VARCHAR(128)

SELECT 
    @context = CAST(CONTEXT_INFO() AS VARCHAR(128)) 
FROM 
    master.dbo.SYSPROCESSES 
WHERE 
    SPID = @@SPID

DECLARE @user VARCHAR(50) = LEFT(@context, 50)

UPDATE users 
SET username = LTRIM(RTRIM(@user)) 
WHERE id = 1

用户名正确设置为“B”,但现在返回50:

SELECT 
    username, LEN(username) 
FROM 
    users 
WHERE 
    id = 1 -- returns: B, 50

在填充上下文时,解决方案是:

set @context = cast('B' + replicate(' ', 126) as varbinary(128))

但为什么我需要这样做?

当我没有用空格填充CONTEXT_INFO时发生的事情是使用其值进行更新将导致结果长度为50(即使我ltrimrtrim单个更新前的字符值)?

为什么我必须将CONTEXT_INFO填充到127个字节,而不是128个?对于超过127的每个字符,1个字符将从最初在CONTEXT_INFO

上设置的值中截断

注意:启用了ANSI_PADDING

2 个答案:

答案 0 :(得分:1)

在您的代码中:

declare @user varchar(50) = left(@context, 50)
UPDATE users set username = ltrim(rtrim(@user)) WHERE id = 1

您将@user定义为50个字符。由于CONTEXT_INFO本身是128个字节,因此@user的内容将是由49个空B个字符填充的字母CHAR(0)LTRIM()RTRIM()不会删除不是空格的空字符,因此它们对@user没有影响。

如果要删除NULL字符,可以尝试此操作(假设您使用的是SQL Server 2005或更高版本):

UPDATE users SET username = REPLACE(@user, char(0), '')

答案 1 :(得分:0)

我知道这个问题很老了,但是有两种方法可以检索 CONTEXT_INFO:直接使用 CONTEXT_INFO() 或从 sys.dm_exec_sessions 检索。后者没有用“0”字符填充。

declare @c varbinary(128)
select  @c = convert(varbinary(128), 'Test context')
set CONTEXT_INFO @c
go

-- option 1: padded with '0'
declare @value varchar(128)
select  @value = convert(varchar(128), CONTEXT_INFO())
select  @value context, len(@value) length
go

-- option 2: NOT padded with '0'
declare @value varchar(128)
select  @value = convert(varchar(128), context_info)
from    sys.dm_exec_sessions
where   session_id = @@SPID
select  @value context, len(@value) length
go

查询结果。

context         length
--------------- -----------
Test context    128

(1 row affected)

context         length
--------------- -----------
Test context    12

(1 row affected)

或者,从 SQL Server 2016 开始,您还可以使用 SESSION_CONTEXT(),它允许您指定键值对,而不是单个二进制 blob。