I'm trying to convert back the nvarchar stored in CONTEXT_INFO.
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));
The nvarchar obtained from casting varbinary to nvarchar is of length 6, it includes the \0. Example, the language 'en' is obtained back as 'en\0\0\0\0'. This mucked up the key caching on NHibernate.
Is there a way we can convert back the nvarchar value stored in varbinary to its original value? i.e., 'en' can be converted back to 'en'.
Output:
A
-----------
2
B
-----------
2
C
------
en
D
-----
en
E
-----------
6
F
-----------
6
G
------------------------------
en
H
------------------------------
en
I
-----------
30
J
-----------
30
CHOSEN ANSWER rationale
I chose HABO's answer as his solution is directly embeddable to consuming queries:
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);
Output:
dump
--------------------
0x0000000465006E00
(1 row(s) affected)
recoveredLanguage theLength
------------------------------ -----------
en 2
(1 row(s) affected)
recoveredLanguage theLength
----------------- -----------
en 2
(1 row(s) affected)
While souplex's answer is correct, I'm not certain if SET ANSI_PADDING_OFF effects globally, or local only on one batch of statements. And placing all the castings in one statement has side effect, the restoration doesn't work, each casting must be done on separate statements. I upvote souplex's answer anyway
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);
Output:
dump
----------
0x65006E00
(1 row(s) affected)
recoveredLanguage theLength
----------------- -----------
en 6
(1 row(s) affected)
recoveredLanguage theLength
----------------- -----------
en 2
(1 row(s) affected)
Kudos to HABO and souplex for not bringing up XML PATH or XML AUTO solution :-) Thanks!