2012-02-24 14 views
9

Estoy tratando de usar CONTEXT_INFO para pasar un usercode de un procedimiento almacenado a un desencadenador DELETE para fines de auditoría de tabla.Casting CONTEXT_INFO para varchar y la longitud resultante

Todo funciona bien, sin embargo, noté que la longitud del código de usuario guardado en la tabla de auditoría no era correcta.

Tome este script como un ejemplo ...

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 

Resultados:

len (@userCode) = 8

len (@temp_userCode) = 50

¿Por qué regresa la variable @temp_userCode con una longitud de 50, y cómo puedo recortarla a su longitud original para almacenarla? ¿Ctly?

información:

que ejecuta SQL Server 2005, sin embargo, la solución tiene que trabajar en todas las versiones 2005 y siguientes.

Respuesta

6

Cuando se asigna a CONTEXT_INFO que se rellena con bytes nulos 0x00 a 128 bytes de longitud y se convierte en 0x5465737455736572000000...

Puede utilizar

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

Esto funciona sin embargo tuve que cambiar la intercalación de SQL_Latin1_General_CP437_BIN. Esto se basó en prueba y error, sin embargo, que no me deja con mucha confianza. ¿Cómo puedo aclarar qué colación debo usar? –

+0

@Poz: no indicó la versión de SQL Server en su pregunta. Si antes de 2008, las intercalaciones '100' no estarán disponibles. –

+0

Disculpas. Estoy ejecutando 2005, sin embargo, también debe ser adecuado para todas las versiones anteriores. –

3

Se pone rellena con CHAR(0). Proveedores:

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

(EDITAR: se ha añadido una cláusula explícita COLLATE, aunque ahora me siento como si estuviera robando a Martin.)

+0

+1 Utilizo una cláusula explícita de conversión e intercalación en mi respuesta [debido a este problema] (https://connect.microsoft.com/SQLServer/feedback/details/708179/indefinite-hang-with-replace-statement-on -varbinary-max) pero solo apareció para 'varbinary (max)' de todos modos. –

+0

Esta solución no funciona para mí, la longitud sigue siendo 50. ¿Debido a SQL 2005 quizás? –

+0

En realidad, encontré dos: uno con 9.00.3042, el otro con 9.00.4211, y funcionó: ambas longitudes muestran 8. –

0

Reemplazar fallará al azar en diferentes instalaciones de servidor SQL unless you specify the collation:

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

servidor SQL tiene dos comportamientos diferentes, dependiendo de la forma en que está instalado:

  • El reemplazo se realiza correctamente cuando se utiliza la intercalación de SQL.
  • La sustitución no es correcta cuando se utiliza la intercalación de Windows. Hace

Este comportamiento se presentó a Microsoft casi más de 7 años:

Q: Al tratar un reemplazar un carácter NUL con replace(), esto funciona es el valor tiene un SQL intercalación, pero no una intercalación de Windows .

A: Esto se debe al hecho de que 0x0000 es un carácter indefinido en Windows colaciones. Todos los caracteres indefinidos se ignoran durante la comparación, clasificación, y coincidencia de patrón. Entonces buscar 'a' + char (0) realmente está buscando 'a', y la búsqueda de caracteres (0) es equivalente a una cadena vacía.

La manera de manejar carácter indefinido es un poco confuso, pero esta es la forma en que Windows definido para ordenarlos, y SQL Server se ajusta a la API de Windows en general.

En la intercalación de SQL, no existe la noción de caracteres no definidos. A cada código punto se le asigna un peso, por eso no vemos un problema allí.

2

probar esto, a mí me funciona en SQL Server 2005:

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

No hay colaciones desordenado a tener en cuenta :-)

Cuestiones relacionadas