Firebird Documentation Index → Guida sull'uso di NULL nel linguaggio SQL di Firebird → Funzioni definite dall'utente (UDF) |
Le funzioni definite dell'utente, o
UDF (User Defined Functions)
sono funzioni che non sono interne al motore, ma definite in moduli
separati. Firebird arriva con due librerie UDF: ib_udf
(ampiamente usata dai tempi di
InterBase) e fbudf
. Si possono
aggiungere altre librerie, comprandole o scaricandole da internet, oppure
scrivendosele in un qualche linguaggio di programmazione idoneo. Le UDF
non possono essere usate così come sono; devono essere prima
«dichiarate» al database. Questo è vero anche per le UDF che
vengono con Firebird.
Non fa parte degli scopi di questa guida insegnare, usare o
scrivere le UDF. Tuttavia è necessario avvertire che le UDF possono
occasionalmente effettuare inaspettatamente delle conversioni da e verso
NULL
. Questo comporta che alle volte un
NULL
in input possa essere convertito in un valore
regolare particolare, ed altre volte che un valore valido come una
stringa vuota venga null
ificato.
La causa principale di questo problema è che il modo di chiamare
le UDF di «vecchio tipo» (ereditata da Interbase) non è in
grado di passare un NULL
in input ad una funzione.
Quando una funzione UDF quale ad esempio LTRIM
(elimina gli spazi eccedenti a sinistra) viene chiamata con un argomento
NULL
, l'argomento viene passato alla funzione come
una stringa vuota. (Nota: in Firebird 2 e successivi,
può essere passata come un puntatore nullo; ma ci
ritorniamo più oltre). Dall'interno della funzione non esiste
nessun modo per determinare se l'argomento è veramente una
stringa vuota oppure un NULL
. Pertanto che dovrebe
fare chi scrive la routine? Deve fare una scelta: o prendere il valore
come gli arriva o assumere che fosse originariamente un
NULL
e trattarlo di conseguenza.
Se il tipo risultato di una funzione è un puntatore, è possibile
ottenere NULL
da una funzione anche se non è
possibile passarglielo. A tal punto che potrebbero accadere i seguenti
fenomeni inattesi:
Si chiama una UDF con un argomento a
NULL
. Viene passato alla funzione con un
valore, cioè 0 oppure ''
. All'interno della
funzione questo valore non è ricambiato in
NULL
; pertanto viene riportato un risultato
non-NULL
.
Si chiama una UDF con un argomento valido come 0 oppure
''
, questo viene passato come è, ovviamente. Ma
il codice della funzione suppone che sia invece la rappresentazione
di un NULL
, lo tratta come un buco nero, e
riporta al chiamante un NULL
.
Entrambe le conversioni sono normalmente indesiderate, ma la
seconda probabilmente lo è di più della prima (è meglio validare
qualcosa che è NULL piuttosto che NULLificare qualcosa di valido). Per
tornare al nostro esempio della LTRIM
: in Firebird
1.0 questa funzione riporta NULL
per una stringa
vuota, che è sbagliato; nella versione 1.5, non riporta mai
NULL
: in questa versione, anche le stringhe
NULL
sono cambiate in stringhe vuote. Intediamoci,
pure questo è sbagliato, ma è considerato il minore dei due mali. In
Firebird 2 finalmente funziona bene: una stringa NULL dà un risultato
NULL, una stringa vuota viene ridotta ad una stringa vuota, semprechè si
dichiari la funzione nella giusta maniera.
Fin da Firebird 1.0, è stato introdotto un nuovo metodo di passare
gli argomenti ed i risultati con le UDF: «per descrittore».
I descrittori permettono di segnalare la presenza di un
NULL
indipendentemente dal tipo di dato. La
libreria fbudf
fa ampio uso di
questa tecnica. Sfortunatamente, usare i descrittori è un po'
complicato; è necessario più lavoro ed è men o piacevole per lo
sviluppatore dell'UDF. D'altra parte si è in grado di risolvere tutti i
tradizionali problemi legati al NULL
, e per il
chiamante è semplice come per le UDF standard di vecchio stile.
Firebird 2 ha migliorato il sistema di chiamare le UDF di vecchio
tipo. Il sistema adesso passa un NULL
di input alla
funzione come un puntatore nullo, se la
funzione è stata dichiarata al database con una parola chiave
NULL dopo l'argomento in questione:
declare external function ltrim
cstring(255) null
returns cstring(255) free_it
entry_point 'IB_UDF_ltrim' module_name 'ib_udf';
Questa richiesta assicura che i database esistenti e le loro relative applicazioni continuino a funzionare come prima. Omettendo la parola chiave NULL la funzione si comporterà esattamente come avrebbe fatto in Firebird 1.5.
Notare che non è sufficiente aggiungere il
NULL alla dichiarazione e pensare che una qualsiasi
funzione gestisca correttamente il NULL
in
ingresso. Ogni funzione deve essere anche riscritta in modo tale da
gestire correttamente il NULL
nel nuovo modo.
Bisogna sempre osservare le dichiarazioni date dallo sviluppatore della
funzione. Per le funzioni della libreria ib_udf
, consultare il file
ib_udf2.sql
che è nel sottodirettorio UDF
di Firebird. Notare il
2
nel nome del file; le dichiarazioni vecchio stile
sono in ib_udf.sql
.
Le seguenti funzioni della libreria ib_udf
sono state aggiornate per
riconoscere il NULL
in input e gestirlo in modo
proprio:
ascii_char
lower
lpad
e rpad
ltrim
e rtrim
substr
e
substrlen
Molte funzioni ib_udf
rimangono tali e quali; in ogni caso, passare NULL
ad una UDF di vecchio stile è impossibile se l'argomento non è di tipo
per riferimento.
Una nota a latere: è sconsigliato usare le funzioni UDF
lower
, .trim
e
substr*
nel nuovo codice; è preferibile invece
usare le funzioni interne LOWER,
TRIM e SUBSTRING.
Usando sotto Filrebird 2 una o più funzioni listate sopra con un
database preesistente, e volendo beneficiare della nuova gestione dei
NULL
, bisogna eseguire nel proprio database i
comandi preparati in ib_udf_upgrade.sql
. Lo si
può trovare nella directory di Firebird
misc\upgrade\ib_udf
.
Le conversioni non richieste NULL
<–>
non-NULL
descritte
precedentemente normalmente accadono con le UDF compatibili, ma ce ne
sono molte in giro (sopratutto nella ib_udf
). Inoltre nulla può fermare un
programmatore superficiale dal ricadere nello stesso errore in una
funzione nel nuovo stile. Pertanto il comportamento più sicuro da tenere
se si usa una UDF e non si conosce come si comporta nei confronti del
NULL
:
guardare alla sua dichiarazione per controllare come sono passati e riportati i suoi valori. Se dice «by descriptor», si comporta in modo corretto (sebbene non fa mai male assicurarsene). Idem se sono seguiti dalla parola chiave NULL. In tutti gli altri casi, verificate i passi seguenti.
Avendone i sorgenti, e sapendo leggere il linguaggio in cui è scritto (C, C++, Delphi,...) controllare cosa fa il codice della funzione.
Valutare la funzione con valori NULL
e
con valori come 0 (per argomenti numerici) e/o ''
(per stringhe).
Se la funzione effettua una conversione indesiderata
NULL
<-> non-NULL
,
bisogna girarci intorno nel proprio codice prima di chiamare la UDF
(vedere anche Come controllare se ci sono
NULL
, altrove in questa
guida).
Le dichiarazioni per le UDF rilasciate possono essere trovate nel
sottodirettorio di Firebird examples
(per la versione 1.0) oppure
UDF
(dalla versione 1.5 in poi):
si trovano nei files con estensione .sql
Per ottenere informazioni più approfondite sulle UDF, si possono consultare i documenti (al momento tutti in inglese) InterBase 6.0 Developer's Guide (gratuito, scaricabile da http://www.ibphoenix.com/downloads/60DevGuide.zip), Using Firebird e la Firebird Reference Guide (entrambi su CD), oppure il Firebird Book. I CD ed il libro possono essere acquistati attraverso http://www.ibphoenix.com.
Firebird Documentation Index → Guida sull'uso di NULL nel linguaggio SQL di Firebird → Funzioni definite dall'utente (UDF) |