Hystrix


Il mondo è la totalità dei fatti non delle cose.
Archivio Posts
Anno 2018

Anno 2016

Anno 2015

Anno 2009

Anno 2008

Anno 2007

Anno 2006
Statistiche
  • Views Home Page: 56.012
  • Views Posts: 105.663
  • Views Gallerie: 0
  • n° Posts: 41
  • n° Commenti: 84

Cast e Convert

Su microsoft.public.it.sql si discute spesso di casting e formattazione [in special modo di date e numeri] e, mi pare, ne emerge spesso una discreta confusione. La questione è delicata e ha a che fare direttamente con le performances, tuttavia la sintassi TSQL sovrappone fortemente le due problematiche contribuendo a aumentare il disorientamento. In compenso VS.Net ha reso la sintassi in questo senso cristallina e quindi, un programmatore C# o VB.Net non dovrebbe aver problemi a trovare naturale la distinzione.

Partiamo da un tipico casting TSQL:

declare @i tinyint
set @i=100
select convert(varchar,@i)

E analizziamone ogni passaggio:

declare @i tinyint

Richiede l'allocazione di un byte di memoria per l'assegnazione di un valore numerico positivo compreso tra 0 e 255. Si tratta quindi di 8 bit in cui lo zero è rappresentato dalla sequenza 00000000.

set @i=100

100, in forma binaria ha la struttura 1100100, quindi il byte in questione viene popolato, supponendo un senso di lettura naturale da sinitra a destra, come 01100100.

Ora viene la parte delicata.
Tecnicamente, castare 01100100 su di una stringa vorrebbe dire "reinterpretare la sequenza di bit come stringa", cioè eseguire un cambiamento tutto lato codice che permetta di applicare le funzioni dedicate alle stringhe a quell'area di memoria che era dedicata a un tinyint, SENZA PORTARE ALCUNA ALTERAZIONE all'area di memoria stessa.
Quindi poiché anche le stringhe hanno ovviamente una rappresentazione in memoria basate su sequenze di bit, il cast in questione dovrebbe generare la stringa che ha come rappresentazione bit la sequenza 01100100.
E poiché la rappresentazione binaria delle stringhe è basata sulle tabelle di codici ASCII e il codice ASCII di posizione 100 è una 'd', a rigore, il nostro:

select convert(varchar,@i)

dovrebbe tornare 'd', e non '100'!

Va da se che questo tipo di conversione avrebbe un uso estremamente limitato e, giustamente, ambienti rigorosi come VS.NET semplicemente lo vietano, quindi non è possibile scrivere, in C#, una cosa del tipo:

byte i=1;
string x=(string)i;

Dovrebbe a questo punto essere chiaro che la pseudo-conversione attesa dal valore 100 alla stringa '100', è in realtà una funzione complessa in grado di determinare la forma in base dieci del valore binario 01100100 e darne una rappresentazione basata sulle tabelle ASCII, cioè una funzione in grado ti manipolare 01100100 e trasformarlo in 001100010011000000110000.
Si osservi come non solo l'area di memoria è stata modificata nel contenuto ma anche estesa [triplicata!] generando una struttura che potremmo, per controllo, dividere in byte:

00110001-00110000-00110000

Convertire ogni byte nel proprio valore decimale:

49-48-48

Cercare sulle tabelle ACII i corrispondenti caratteri di 49 e 48 e ottenere:

'1'-'0'-'0'

e quindi il nostro '100'

La controprova si ottiene passando attraverso una conversione in binary, tipo neutro che comporta sempre una conversione pura:

select convert(binary(3),'100')

che ritorna '0x313030' e cioè la rappresentazione esadecimale del binario 001100010011000000110000.

Quindi passare dal valore 100 alla stringa '100' non è un cast ne una conversione ma l'applicazione di una funzione complessa che richiede l'occupazione di memoria aggiuntiva e questo fatto è reso cristallino in .Net con l'introduzione della funzione fondamentale ToString() e obbligando a scrivere esplicitamente:

byte i=1;
string x=i.Totring();

In modo del tutto analogo non ha senso la conversione contraria dalla stringa '100' al valore 100 richiedendo il passaggio inverso dalla sequenza 001100010011000000110000 alla sequenza 01100100. Ancora una volta, un linguaggio di scripting non rigoroso come il TSQL [ma si faceva anche in VB6] permette di scrivere l'assurdità:

declare @i char(3)
set @i='100'
select convert(tinyint,@i)

mentre linguaggi rigorosi come C# richiedono di esplicitare l'aspetto di funzione, obbligando a scrivere:

string x='100'
byte i=byte.Parse(x);

In TSQL la questione è marginale ma non troppo. Dovrebbe a questo punto essere chiaro, infatti, che, per esempio, un indice su una colonna di byte non può essere utilizzato dopo una conversione verso stringa, venendo generate sequenze di byte completamente diverse.

Avere coscienza di quanto avviene è sicuramente importante per scrivere queries efficienti. Avere un sintassi non ambigua che agevoli l'assunzione di questa coscienza è invece una speranza per una futura versione del TSQL.

Categoria: SQL Server
domenica, 02 lug 2006 Ore. 13.28
Calendario
agosto 2019
lmmgvsd
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678
Ora e Data
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003