2

我正在尝试将存储在 CONTEXT_INFO 中的 nvarchar 转换回。

declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(@LanguageCode as varbinary);
set context_info @binvar;

select A = len(@LanguageCode);
select B = len(convert(nvarchar(6),@LanguageCode));

select C = convert(nvarchar(6),context_info());
select D = cast(CONTEXT_INFO() as nvarchar(5));
select E = len(convert(nvarchar(6),CONTEXT_INFO()));
select F =len(cast(CONTEXT_INFO() as nvarchar(6)));

select G = convert(nvarchar,context_info());
select H = cast(CONTEXT_INFO() as nvarchar);
select I = len(convert(nvarchar,CONTEXT_INFO()));
select J = len(cast(CONTEXT_INFO() as nvarchar));

通过将 varbinary 转换为 nvarchar 获得的 nvarchar 长度为 6,它包括 \0。例如,语言“en”返回为“en\0\0\0\0”。这弄乱了NHibernate上的密钥缓存。

有没有办法可以将存储在 varbinary 中的 nvarchar 值转换回其原始值?即,“en”可以转换回“en”。

输出:

A
-----------
2

B
-----------
2

C
------
en    

D
-----
en   

E
-----------
6

F
-----------
6

G
------------------------------
en                            

H
------------------------------
en                            

I
-----------
30

J
-----------
30

选择答案的理由

我选择了 HABO 的答案,因为他的解决方案可以直接嵌入到消费查询中:

declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(datalength(@LanguageCode) as varbinary) + cast(@LanguageCode as varbinary);
set context_info @binvar;
select dump = @binvar;



-- directly embeddable
select  recoveredLanguage = convert(nvarchar, substring(context_info(), 5, convert(int, substring(context_info(), 1, 4)) )  ) 
        , theLength =  len ( convert(nvarchar, substring(context_info(), 5, convert(int, substring(context_info(), 1, 4)) )  ) )


declare @buffer varbinary(128) = context_info();
declare @RecoveredLanguageCode nvarchar(6) = cast(substring(@buffer, 5, cast(substring(@buffer, 1, 4) as int)) as nvarchar(6));
select recoveredLanguage = @RecoveredLanguageCode, theLength = len(@RecoveredLanguageCode);

输出:

dump
--------------------
0x0000000465006E00

(1 row(s) affected)

recoveredLanguage              theLength
------------------------------ -----------
en                             2

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                2

(1 row(s) affected)

虽然 souplex 的回答是正确的,但我不确定 SET ANSI_PADDING_OFF 是全局影响,还是仅对一批语句产生局部影响。并且将所有铸件放在一个语句中会产生副作用,恢复不起作用,每个铸件必须在单独的语句中完成。无论如何我都赞成souplex的回答

DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;
select dump = @Binvar;




SET ANSI_PADDING OFF;
select recoveredLanguage = cast( cast( cast(context_info() as binary(128)) as varbinary(128) ) as nvarchar(6) )
        , theLength = len( cast( cast( cast(context_info() as binary(128)) as varbinary(128) ) as nvarchar(6) ) );


DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
declare @c nvarchar(6) = cast(@binvar2 as nvarchar(6))
select recoveredLanguage = @c, theLength = len(@c);

输出:

dump
----------
0x65006E00

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                6

(1 row(s) affected)

recoveredLanguage theLength
----------------- -----------
en                2

(1 row(s) affected)

感谢 HABO 和 souplex 没有提出 XML PATH 或 XML AUTO 解决方案 :-) 谢谢!

4

2 回答 2

3

在将字符串保存之前为字符串加上长度前缀CONTEXT_INFO

declare @LanguageCode nvarchar(6) = 'en';
declare @binvar varbinary(128);
set @binvar = cast(datalength(@LanguageCode) as varbinary) + cast(@LanguageCode as varbinary);
set context_info @binvar;

declare @buffer varbinary(128) = context_info();
declare @RecoveredLanguageCode nvarchar(6) = cast(substring(@buffer, 5, cast(substring(@buffer, 1, 4) as int)) as nvarchar(6));
select @RecoveredLanguageCode, len(@RecoveredLanguageCode);
于 2013-06-16T03:02:03.987 回答
2

常规的 varbinary(128) 将是完全可转换的。

DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY);
SELECT  CAST(@binvar AS NVARCHAR(6));

这将返回初始值“en”。

现在,当您设置上下文值并将其取回时,它似乎已经变成了 binary(128) 值而不是 varbinary(128)。

SET context_info @binvar;
SELECT  CAST(context_info() AS NVARCHAR(6));

现在你有尾随 char(0) 字符。

当您将 context_info() 值转换为 varbinary 并将其转换为 nvarchar 时,当您将 ansi 填充显式设置为关闭时,您的问题就解决了。

SET ANSI_PADDING OFF;
--
DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;

SET ANSI_PADDING ON;
DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
--> having trailing char(0)
SELECT  CAST(@binvar2 AS NVARCHAR(6));

GO

DECLARE @LanguageCode NVARCHAR(6) = 'en';
DECLARE @binvar VARBINARY(128);
SET @binvar = CAST(@LanguageCode AS VARBINARY(128));
SET context_info @binvar;

SET ANSI_PADDING OFF;
DECLARE @binvar1 BINARY(128) = context_info();
DECLARE @binvar2 VARBINARY(128) = CAST(@binvar1 AS VARBINARY(128));
--> no more trailing char(0)
SELECT  CAST(@binvar2 AS NVARCHAR(6));
于 2013-06-16T03:22:01.567 回答