Firebird Documentation IndexGuida sull'uso di NULL nel linguaggio SQL di Firebird → Funzioni definite dall'utente (UDF)
Firebird Home Firebird Home Indietro: SELECT DISTINCTFirebird Documentation IndexRisali: Guida sull'uso di NULL nel linguaggio SQL di FirebirdAvanti: Convertire da e verso NULL

Funzioni definite dall'utente (UDF)

Conversioni NULL <–> non-NULL non richieste
Descrittori
Miglioramenti di Firebird 2
Prepararsi alle conversioni non desiderate
Altre informazioni sulle 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.

Conversioni NULL <–> non-NULL non richieste

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 nullificato.

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.

Descrittori

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.

Miglioramenti di Firebird 2

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.

«Aggiornare» le funzioni della libreria ib_udf in un database esistente

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.

Prepararsi alle conversioni non desiderate

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:

  1. 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.

  2. Avendone i sorgenti, e sapendo leggere il linguaggio in cui è scritto (C, C++, Delphi,...) controllare cosa fa il codice della funzione.

  3. Valutare la funzione con valori NULL e con valori come 0 (per argomenti numerici) e/o '' (per stringhe).

  4. 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

Altre informazioni sulle UDF

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.

Indietro: SELECT DISTINCTFirebird Documentation IndexRisali: Guida sull'uso di NULL nel linguaggio SQL di FirebirdAvanti: Convertire da e verso NULL
Firebird Documentation IndexGuida sull'uso di NULL nel linguaggio SQL di Firebird → Funzioni definite dall'utente (UDF)