Supporto per le eccezioni e i messaggi di errore
Qualsiasi errore che si verifica in una procedura NZPLSQL interrompe l'esecuzione della procedura e interrompe anche la transazione circostante. Il sistema torna al ciclo principale per ottenere la domanda successiva dall'applicazione client. Non è possibile catturare tutte le eccezioni, soprattutto se l'azione lascia il database in un cattivo stato.
Per catturare ed elaborare un errore che si verifica in un blocco di procedura, si può aggiungere una sezione di gestione delle eccezioni alla fine di un blocco utilizzando la parola chiave EXCEPTION. Se non si verifica alcun errore, la sezione di gestione delle eccezioni viene ignorata. All'interno della sezione di gestione delle eccezioni, è possibile specificare uno o più gestori di eccezioni utilizzando le clausole WHEN, che specificano l'eccezione a cui corrispondere e le istruzioni da eseguire quando si verifica una corrispondenza. Una dichiarazione di ECCEZIONE ha la seguente forma:
EXCEPTION
WHEN clause THEN
statements
[ WHEN ... ]
NZPLSQL supporta due clausole per l'elaborazione delle eccezioni:
- TRANSAZIONE_ABORTITA
- Usare la clausola TRANSACTION_ABORTED per specificare le istruzioni da eseguire quando si verifica un errore che causa l'interruzione della transazione. In questo caso, per continuare è necessario un ROLLBACK. Assicuratevi che il comando ROLLBACK sia il primo comando nelle istruzioni di gestione delle eccezioni.
- ALTRI
- Usare la clausola OTHERS per specificare le istruzioni da eseguire quando si verifica un errore all'interno del blocco di procedura. Errori come un errore di parsing SQL non interrompono la transazione e quindi non corrispondono a una clausola TRANSACTION_ABORTED.
È possibile specificare entrambe le clausole in un blocco di eccezione, come nell'esempio seguente. Quando si verifica un errore nella procedura, il codice della procedura utilizza la prima clausola di eccezione corrispondente ed esegue le istruzioni contenute in tale clausola. Tutte le clausole dopo la corrispondenza vengono ignorate. Come prassi ottimale, specificare la clausola OTHERS per ultima, perché corrisponde a qualsiasi tipo di errore.
EXCEPTION
WHEN TRANSACTION_ABORTED THEN
ROLLBACK;
statements_case1
RAISE ERROR 'Procedure failed: %', sqlerrm;
WHEN OTHERS THEN
statements_case2
RAISE NOTICE 'Caught error, continuing %', sqlerrm;
In questo esempio, un errore che interrompe una transazione attiva la clausola TRANSACTION_ABORTED e la stored procedure esegue il ROLLBACK, le istruzioni in statements_case1 e visualizza il messaggio di errore. Se l'errore non ha causato l'interruzione della transazione, l'elaborazione dell'eccezione salta alla clausola OTHERS e la stored procedure esegue l'insieme statements_case2 e genera il messaggio di avviso. Se non ci sono errori nel blocco, le dichiarazioni di eccezione vengono saltate.
La variabile SQLERRM contiene il testo di un messaggio di errore che viene catturato. In assenza di un blocco di eccezione, l'eccezione si propaga fino alla procedura memorizzata successiva nello stack delle chiamate. Se sproc1 chiama sproc2, che genera un'eccezione, ma sproc2 non ha un gestore di eccezioni, il sistema cerca un gestore in sproc1. Il sistema esamina anche le dichiarazioni del blocco che lo racchiude.
create or replace procedure sp_except01() returns BOOL LANGUAGE
NZPLSQL AS
BEGIN_PROC
DECLARE
r record;
BEGIN
<<inner>>
BEGIN
SELECT * INTO r FROM NONEXISTENT;
END;
END;
END_PROC;
create or replace procedure sp_except02() returns BOOL LANGUAGE
NZPLSQL AS
BEGIN_PROC
BEGIN
CALL sp_except01();
END;
END_PROC;
create or replace procedure sp_except03() returns BOOL LANGUAGE
NZPLSQL AS
BEGIN_PROC
BEGIN
CALL sp_except02();
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Caught exception';
END;
END_PROC;
In questi esempi, l'eccezione viene generata in sp_except01, nel blocco interno. Il sistema verifica innanzitutto la presenza di un gestore di eccezioni per il blocco interno, che non viene trovato. Il controllo passa al contesto padre, che è la procedura sp_except01, e nemmeno lì viene trovato un gestore di eccezioni. Il controllo passa quindi a sp_except02 e infine a sp_except03, dove viene trovato e utilizzato un gestore di eccezioni.
Se un'eccezione non viene catturata a nessun livello, vengono inviati ulteriori messaggi di log a livello di AVVISO per fornire il contesto dell'errore e il punto in cui si è verificato (numero di riga e tipo di istruzione, a meno che l'errore non provenga da un'istruzione RAISE EXCEPTION).
CREATE PROCEDURE sp() RETURNS INTEGER LANGUAGE NZPLSQL AS
BEGIN_PROC
BEGIN
EXECUTE IMMEDIATE 'insert into NOTEXIST' || 'values(1,1)';
EXCEPTION WHEN OTHERS THEN
END;
END_PROC;
Supponendo che NOTEXIST non esista nel database, la query non visualizza alcun errore perché l'errore è stato gestito dal gestore di eccezioni.
CREATE PROCEDURE sp() RETURNS INTEGER LANGUAGE NZPLSQL AS
BEGIN_PROC
BEGIN
EXECUTE IMMEDIATE 'insert into NOTEXIST' || ' values(1,1)';
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Got exception: %', SQLERRM;
END;
END_PROC;NOTICE: Got exception: ERROR: Relation 'NOTEXIST' does not exist