2012-02-24 12 views
9

Sto provando a utilizzare CONTEXT_INFO per passare un codice di accesso da una stored procedure a un trigger DELETE per scopi di controllo tabella.Trasmettere CONTEXT_INFO a varchar e la lunghezza risultante

Funziona tutto bene, tuttavia ho notato che la lunghezza del codice di accesso salvato nella tabella di controllo non era corretta.

Prendete questo script come un esempio ...

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 

Risultati:

len (@userCode) = 8

len (@temp_userCode) = 50

Perché la variabile @temp_userCode torna con una lunghezza di 50 e come posso ridimensionarla alla sua lunghezza originale per memorizzarla cor ctly?

Ulteriori informazioni:

esecuzione di SQL Server 2005, tuttavia la soluzione deve funzionare in tutte le versioni dal 2005 in poi.

risposta

6

Quando viene assegnato a CONTEXT_INFO ottiene riempito con byte nullo 0x00 a 128 byte e diventa 0x5465737455736572000000...

È possibile utilizzare

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

Questo funziona però ho dovuto cambiare le regole di confronto a SQL_Latin1_General_CP437_BIN. Questo è stato basato su tentativi ed errori, tuttavia, che non mi lascia con molta fiducia. Come posso chiarire quale collation dovrei usare? –

+0

@Poz: non hai indicato la versione di SQL Server nella tua domanda. Se precedente al 2008 le collazioni "100" non saranno disponibili. –

+0

Scuse. Sto lavorando nel 2005, tuttavia deve essere adatto a tutte le versioni precedenti. –

3

Esso viene riempita con CHAR(0). Prova:

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

(EDIT: aggiunta una clausola di COLLATE esplicito, anche se ora mi sento come se rubare da Martin.)

+0

+1 Nella mia risposta utilizzo una clausola esplicita di cast e fascicolazione [a causa di questo problema] (https://connect.microsoft.com/SQLServer/feedback/details/708179/indefinite-hang-with-replace-statement-on -varbinary-max) ma è apparso solo per 'varbinary (max)' comunque. –

+0

Questa soluzione non funziona per me, la lunghezza è ancora 50. A causa di SQL 2005 forse? –

+0

In realtà ho trovato due - uno in esecuzione 9.00.3042, l'altro 9.00.4211, e ha funzionato - entrambe le lunghezze mostrano 8. –

0

Sostituire in modo casuale fallire su diverse installazioni di SQL server unless you specify the collation:

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

SQL server ha due comportamenti differenti, a seconda di come è installato:

  • La sostituzione viene eseguita correttamente quando si utilizzano le regole di confronto SQL.
  • La sostituzione non ha esito positivo quando vengono utilizzate le regole di confronto di Windows.

Questo comportamento è stato sottoposto a Microsoft quasi oltre 7 anni fa:

D: Quando si cerca una sostituire un carattere NUL con replace(), in cui funziona è il valore ha uno SQL regole di confronto, ma non un confronto di Windows .

A: Ciò è dovuto al fatto che il 0x0000 è un carattere indefinito in Windows regole di confronto. Tutti i caratteri non definiti vengono ignorati durante il confronto, l'ordinamento, e la corrispondenza del modello. Quindi, cercando ' ' a '+ char (0) è davvero alla ricerca di ' a ', e la ricerca di char (0) è equivalente alla stringa vuota.

Il modo per gestirle carattere indefinito è un po 'di confusione, ma questo è il modo in cui Windows definito per ordinarli, e SQL Server è conforme alla generale API di Windows.

Nelle regole di confronto SQL, non vi è alcuna nozione di carattere non definito. Ad ogni codice viene assegnato un peso, ecco perché non vediamo un problema lì.

2

Prova questa, per me funziona su SQL Server 2005:

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

Nessun collations disordinato da considerare :-)