【问题标题】:SQL Server, CONTEXT_INFO(), and varchar sizeSQL Server、CONTEXT_INFO() 和 varchar 大小
【发布时间】:2016-01-22 01:15:56
【问题描述】:

在表users 中,我有一个数据类型为varchar(50) 的列username。该表没有记录。我为用户名插入一条带有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 的字符,从 CONTEXT_INFO 最初设置的值中截断 1 个字符

注意:ANSI_PADDING 已启用

【问题讨论】:

    标签: sql-server context-info


    【解决方案1】:

    在您的代码中:

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

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

    如果您想删除NULL 字符,您可以试试这个(假设您使用的是 SQL Server 2005 或更高版本):

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

    【讨论】:

    • 没有将值转换为不允许 NULL 字节的类型,有没有一种简单的方法可以删除所有尾随 NULL 字节?
    • 如果您从 128 字节的空填充 CONTEXT_INFO 中选择 50 个字节,那么您希望使用什么作为填充而不是 NULL?如果您不想要填充,则只需选择确切的长度。
    • 但是我怎么知道有多少非 NULL 字符被传递到 CONTEXT_INFO 中呢?在我的示例中,传递的值是硬编码的,但在实时代码中,CONTEXT_INFO 是使用动态数据填充的。
    • 因为我的触发器不知道 CONTEXT_INFO 中是否有 1 个或 127 个字节(在我上面的示例中,它是硬编码的,但在生产中它将是动态的)我最终做了以下事情:set @ 987654334@@context) if @start > 0 set @context = left(@context, @start) 这可能比计算每个可能在 context_info 上设置值的位置附加多少空格字符要好。
    【解决方案2】:

    我知道这个问题很老,但是有两种方法可以检索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。

    【讨论】:

      猜你喜欢
      • 2019-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-21
      相关资源
      最近更新 更多