CATEGORII DOCUMENTE |
Tratarea erorilor
Mecanismul de gestiune a erorilor permite utilizatorului sa defineasca si sa controleze comportamentul programului atunci cand acesta genereaza o eroare. In acest fel, aplicatia nu este oprita, revenind intr-un regim normal de executie.
Intr-un program PL/SQL pot sa apara erori la compilare sau erori la executie.
Erorile care apar in timpul compilarii sunt detectate de motorul PL/SQL si sunt comunicate programatorului care va face corectia acestora. Programul nu poate trata aceste erori deoarece nu a fost inca executat.
Erorile care apar in timpul executiei nu mai sunt tratate interactiv. In program trebuie prevazuta aparitia unei astfel de erori si specificat modul concret de tratare a acesteia. Atunci cand apare eroarea este declansata o exceptie, iar controlul trece la o sectiune separata a programului, unde va avea loc tratarea erorii.
Gestiunea erorilor in PL/SQL face referire la conceptul de exceptie. Exceptia este un eveniment particular (eroare sau avertisment) generat de server-ul Oracle sau de aplicatie, care necesita o tratare speciala. In PL/SQL mecanismul de tratare a exceptiilor permite programului sa isi continue executia si in prezenta anumitor erori.
Exceptiile pot fi definite, activate, tratate la nivelul fiecarui bloc din program (program principal, functii si proceduri, blocuri interioare acestora). Executia unui bloc se termina intotdeauna atunci cand apare o exceptie, dar se pot executa actiuni ulterioare aparitiei acesteia, intr-o sectiune speciala de tratare a exceptiilor.
Posibilitatea de a da nume fiecarei exceptii, de a izola tratarea erorilor intr-o sectiune particulara, de a declansa automat erori (in cazul exceptiilor interne) imbunatateste lizibilitatea si fiabilitatea programului. Prin utilizarea exceptiilor si rutinelor de tratare a exceptiilor, un program PL/SQL devine robust si capabil sa trateze atat erorile asteptate, cat si cele neasteptate ce pot aparea in timpul executiei.
Sectiunea de tratare a erorilor
Pentru a gestiona exceptiile, utilizatorul trebuie sa scrie cateva comenzi care preiau controlul derularii blocului PL/SQL. Aceste comenzi sunt situate in sectiunea de tratare a erorilor dintr-un bloc PL/SQL si sunt cuprinse intre cuvintele cheie EXCEPTION si END, conform urmatoarei sintaxe generale:
EXCEPTION
WHEN nume_exceptie [OR nume_exceptie2 .] THEN
secventa_de_instructiuni_1
[WHEN nume_exceptie3 [OR nume_exceptie4 .] THEN
secventa_de_instructiuni_2
.
[WHEN OTHERS THEN
secventa_de_instructiuni_n
END
De remarcat ca WHEN OTHERS trebuie sa fie ultima clauza si trebuie sa fie unica. Toate exceptiile care nu au fost analizate vor fi tratate prin aceasta clauza. Evident, in practica nu se utilizeaza forma WHEN OTHERS THEN NULL.
In PL/SQL exista doua tipuri de exceptii:
exceptii interne, care se produc atunci cand un bloc PL/SQL nu respecta o regula Oracle sau depaseste o limita a sistemului de operare;
exceptii externe definite de utilizator (user-defined error), care sunt declarate in sectiunea declarativa a unui bloc, subprogram sau pachet si care sunt activate explicit in partea executabila a blocului PL/SQL.
Exceptiile interne PL/SQL sunt de doua tipuri:
exceptii interne predefinite (predefined Oracle Server error);
exceptii interne nepredefinite (non-predefined Oracle Server error).
Functii pentru identificarea exceptiilor
Indiferent de tipul exceptiei, aceasta are asociate doua elemente:
un cod care o identifica;
un mesaj cu ajutorul caruia se poate interpreta exceptia respectiva.
Cu ajutorul functiilor SQLCODE si SQLERRM se pot obtine codul si mesajul asociate exceptiei declansate. Lungimea maxima a mesajului este de 512 caractere.
De exemplu, pentru eroarea predefinita ZERO_DIVIDE, codul SQLCODE asociat este -1476, iar mesajul corespunzator erorii, furnizat de SQLERRM, este "divide by zero error".
Codul erorii este:
un numar negativ, in cazul unei erori sistem;
numarul in cazul exceptiei NO_DATA_FOUND;
numarul 0, in cazul unei executii normale (fara exceptii);
numarul 1, in cazul unei exceptii definite de utilizator.
Functiile SQLCODE si SQLERRM nu se pot utiliza direct ca parte a unei instructiuni SQL. Valorile acestora trebuie atribuite unor variabile locale.
Rezultatul functiei SQLCODE poate fi asignat unei variabile de tip numeric, iar cel al functiei SQLERRM unei variabile de tip caracter. Variabilele locale astfel definite pot fi utilizate in comenzi SQL.
Exemplu
Sa se scrie un bloc PL/SQL prin care sa se exemplifice situatia comentata.
DECLARE
eroare_cod NUMBER;
eroare_mesaj VARCHAR2(100);
BEGIN
.
EXCEPTION
.
WHEN OTHERS THEN
eroare_cod := SQLCODE;
eroare_mesaj := SUBSTR(SQLERRM,1,100);
INSERT INTO erori
VALUES (eroare_cod, eroare_mesaj);
END;
Mesajul asociat exceptiei declansate poate fi furnizat si de functia DBMS_UTILITY.FORMAT_ERROR_STACK.
Exceptii interne
Exceptiile interne se produc atunci cand un bloc PL/SQL nu respecta o regula Oracle sau depaseste o limita a sistemului de exploatare.
Aceste exceptii pot fi independente de structura bazei de date sau pot sa apara datorita nerespectarii constrangerilor statice implementate in structura (PRIMARY KEY, FOREIGN KEY, NOT NULL, UNIQUE, CHECK).
Atunci cand apare o eroare Oracle, exceptia asociata ei se declanseaza implicit. De exemplu, daca apare eroarea ORA-01403 (deoarece o comanda SELECT nu returneaza nici o linie), atunci implicit PL/SQL activeaza exceptia NO_DATA_FOUND. Cu toate ca fiecare astfel de exceptie are asociat un cod specific, ele trebuie referite prin nume.
Exceptii interne predefinite
Exceptiile interne predefinite nu trebuie declarate in sectiunea declarativa si sunt tratate implicit de catre server-ul Oracle. Ele sunt referite prin nume (CURSOR_ALREADY_OPEN, DUP_VAL_ON_INDEX, NO_DATA_FOUND etc.). PL/SQL declara aceste exceptii in pachetul DBMS_STANDARD.
Nume exceptie |
Cod eroare |
Descriere |
ACCES_INTO_NULL |
ORA-06530 |
Asignare de valori atributelor unui obiect neinitializat. |
CASE_NOT_FOUND |
ORA-06592 |
Nu este selectata nici una din clauzele WHEN ale lui CASE si nu exista nici clauza ELSE (exceptie specifica lui Oracle9i). |
COLLECTION_IS_NULL |
ORA-06531 |
Aplicarea unei metode (diferite de EXISTS) unui tabel imbricat sau unui vector neinitializat. |
CURSOR_ALREADY_OPEN |
ORA-06511 |
Deschiderea unui cursor care este deja dechis. |
DUP_VAL_ON_INDEX |
ORA-00001 |
Detectarea unei dubluri intr-o coloana unde acestea sunt interzise. |
INVALID_CURSOR |
ORA-01001 |
Operatie ilegala asupra unui cursor. |
INVALID_NUMBER |
ORA-01722 |
Conversie nepermisa de la tipul sir de caractere la numar. |
LOGIN_DENIED |
ORA-01017 |
Nume sau parola incorecte. |
NO_DATA_FOUND |
ORA-01403 |
Comanda SELECT nu returneaza nici o inregistrare. |
NOT_LOGGED_ON |
ORA-01012 |
Programul PL/SQL apeleaza baza fara sa fie conectat la Oracle. |
SELF_IS_NULL |
ORA-30625 |
Apelul unei metode cand instanta este NULL. |
PROGRAM_ERROR |
ORA-06501 |
PL/SQL are o problema interna. |
ROWTYPE_MISMATCH |
ORA-06504 |
Incompatibilitate intre parametrii actuali si formali, la deschiderea unui cursor parametrizat. |
STORAGE_ERROR |
ORA-06500 |
PL/SQL are probleme cu spatiul de memorie. |
SUBSCRIPT_BEYOND_COUNT |
ORA-06533 |
Referire la o componenta a unui nested table sau varray, folosind un index mai mare decat numarul elementelor colectiei respective. |
SUBSCRIPT_OUTSIDE_LIMIT |
ORA-06532 |
Referire la o componenta a unui tabel imbricat sau vector, folosind un index care este in afara domeniului (de exemplu, -1). |
SYS_INVALID_ROWID |
ORA-01410 |
Conversia unui sir de caractere intr-un ROWID nu se poate face deoarece sirul nu reprezinta un ROWID valid. |
TIMEOUT_ON_RESOURCE |
ORA-00051 |
Expirarea timpului de asteptare pentru eliberarea unei resurse. |
TRANSACTION_BACKED_OUT |
ORA-00061 |
Tranzactia a fost anulata datorita unei interblocari. |
TOO_MANY_ROWS |
ORA-01422 |
SELECT.INTO intoarce mai multe linii. |
VALUE_ERROR |
ORA-06502 |
Aparitia unor erori in conversii, constrangeri sau erori aritmetice. |
ZERO_DIVIDE |
ORA-01476 |
Sesizarea unei impartiri la zero. |
Exemplu
Sa se scrie un bloc PL/SQL prin care sa se afiseze numele artistilor de o anumita nationalitate care au opere de arta expuse in muzeu.
Daca rezultatul interogarii returneaza mai mult decat o linie, atunci sa se trateze exceptia si sa se insereze in tabelul mesaje textul "mai multi creatori".
Daca rezultatul interogarii nu returneaza nici o linie, atunci sa se trateze exceptia si sa se insereze in tabelul mesaje textul "nici un creator".
Daca rezultatul interogarii este o singura linie, atunci sa se insereze in tabelul mesaje numele artistului si pseudonimul acestuia.
Sa se trateze orice alta eroare, inserand in tabelul mesaje textul "alte erori au aparut".
SET VERIFY OFF
ACCEPT national PROMPT 'Introduceti nationalitatea:'
DECLARE
v_nume_artist artist.nume%TYPE;
v_pseudonim artist.pseudonim%TYPE;
v_national artist.national%TYPE:= &national';
BEGIN
SELECT nume, pseudonim
INTO v_nume_artist, v_pseudonim
FROM artist
WHERE national = v_national;
INSERT INTO mesaje (rezultate)
VALUES (v_nume_artist||'-'||v_pseudonim);
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO mesaje (rezultate)
VALUES ('nici un creator');
WHEN TOO_MANY_ROWS THEN
INSERT INTO mesaje (rezultate)
VALUES ('mai multi creatori');
WHEN OTHERS THEN
INSERT INTO mesaje (rezultate)
VALUES ('alte erori au aparut');
END;
SET VERIFY ON
Aceeasi exceptie poate sa apara in diferite circumstante. De exemplu, exceptia NO_DATA_FOUND poate fi generata fie pentru ca o interogare nu intoarce un rezultat, fie pentru ca se refera un element al unui tablou PL/SQL care nu a fost definit (nu are atribuita o valoare). Daca intr-un bloc PL/SQL apar ambele situatii, este greu de stabilit care dintre ele a generat eroarea si este necesara restructurarea blocului, astfel incat acesta sa poata diferentia cele doua situatii.
Exceptii interne nepredefinite
Exceptiile interne nepredefinite sunt declarate in sectiunea declarativa si sunt tratate implicit de catre server-ul Oracle. Ele pot fi gestionate prin clauza OTHERS, in sectiunea EXCEPTION.
Diferentierea acestor erori este posibila doar cu ajutorul codului. Dupa cum s-a mai specificat, codul unei exceptii interne este un numar negativ, in afara de exceptia NO_DATA_FOUND, care are codul +100.
O alta metoda pentru tratarea unei erori interne nepredefinite (diferita de folosirea clauzei OTHERS drept detector universal de exceptii) este utilizarea directivei de compilare (pseudo-instructiune) PRAGMA EXCEPTION_INIT. Aceasta directiva permite asocierea numelui unei exceptii cu un cod de eroare intern. In felul acesta, orice exceptie interna poate fi referita printr-un nume si se pot scrie rutine speciale pentru tratarea acesteia. Directiva este procesata in momentul compilarii, si nu la executie.
Directiva trebuie sa apara in partea declarativa a unui bloc, pachet sau subprogram, dupa definirea numelui exceptiei. PRAGMA EXCEPTION_INIT poate sa apara de mai multe ori intr-un program. De asemenea, pot fi asignate mai multe nume pentru acelasi cod de eroare.
In acest caz, tratarea erorii se face in urmatoarea maniera:
se declara numele exceptiei in partea declarativa sub forma:
nume_exceptie EXCEPTION;
se asociaza numele exceptiei cu un cod eroare standard Oracle, utilizand comanda:
PRAGMA EXCEPTION_INIT (nume_exceptie, cod_eroare);
se refera exceptia in sectiunea de gestiune a erorilor (exceptia este tratata automat, fara a fi necesara comanda RAISE).
Exemplu
Daca exista opere de arta create de un anumit artist, sa se tipareasca un mesaj prin care utilizatorul este anuntat ca artistul respectiv nu poate fi sters din baza de date (violarea constrangerii de integritate avand codul eroare Oracle -2292)
SET VERIFY OFF
DEFINE p_nume = Monet
DECLARE
opera_exista EXCEPTION;
PRAGMA EXCEPTION_INIT(opera_exista,-2292);
BEGIN
DELETE FROM artist WHERE nume = '&p_nume';
COMMIT;
EXCEPTION
WHEN opera_exista THEN
DBMS_OUTPUT.PUT_LINE ('nu puteti sterge artistul cu
numele ' || '&p_nume' || ' deoarece exista in
muzeu opere de arta create de acesta');
END;
SET VERIFY ON
Exceptii externe
PL/SQL permite utilizatorului sa defineasca propriile sale exceptii. Aceste exceptii pot sa apara in toate sectiunile unui bloc, subprogram sau pachet. Exceptiile externe sunt definite in partea declarativa a blocului, deci posibilitatea de referire la ele este asigurata. In mod implicit, toate exceptiile externe au asociat acelasi cod (+1) si acelasi mesaj (USER DEFINED EXCEPTION).
Tratarea unei astfel de erori se face intr-o maniera similara modului de tratare descris anterior. Activarea exceptiei externe este facuta explicit, folosind comanda RAISE insotita de numele exceptiei. Comanda opreste executia normala a blocului PL/SQL si transfera controlul "administratorului" exceptiilor.
Declararea si prelucrarea exceptiilor externe respecta urmatoarea sintaxa:
DECLARE
nume_exceptie EXCEPTION; -- declarare exceptie
BEGIN
RAISE nume_exceptie; --declansare exceptie
-- codul care urmeaza nu mai este executat
EXCEPTION
WHEN nume_exceptie THEN
-- definire mod de tratare a erorii
END
Exceptiile trebuie privite ca niste variabile, in sensul ca ele sunt active in sectiunea in care sunt declarate. Ele nu pot sa apara in instructiuni de atribuire sau in comenzi SQL.
Este recomandat ca fiecare subprogram sa aiba definita o zona de tratare a exceptiilor. Daca pe parcursul executiei programului intervine o eroare, atunci acesta genereaza o exceptie si controlul se transfera blocului de tratare a erorilor.
Exemplu
Sa se scrie un bloc PL/SQL care afiseaza numarul creatorilor operelor de arta din muzeu care au valoarea mai mare sau mai mica cu 100000 decat o valoare specificata. Sa se tipareasca un mesaj adecvat, daca nu exista nici un artist care indeplineste aceasta conditie.
VARIABLE g_mesaj VARCHAR2(100)
SET VERIFY OFF
ACCEPT p_val PROMPT 'va rog specificati valoarea:'
DECLARE
v_val opera.valoare%TYPE := &p_val;
v_inf opera.valoare%TYPE := v_val - 100000;
v_sup opera.valoare%TYPE := v_val
v_numar NUMBER(7);
e_nimeni EXCEPTION;
e_mai_mult EXCEPTION;
BEGIN
SELECT COUNT(DISTINCT cod_autor)
INTO v_numar
FROM opera
WHERE valoare BETWEEN v_inf AND v_sup;
IF v_numar = 0 THEN
RAISE e_nimeni;
ELSIF v_numar > 0 THEN
RAISE e_mai_mult;
END IF;
EXCEPTION
WHEN e_nimeni THEN
:g_mesaj:='nu exista nici un artist cu valoarea
operelor cuprinsa intre '||v_inf ||' si '||v_sup;
WHEN e_mai_mult THEN
:g_mesaj:='exista '||v_numar||' artisti cu valoarea
operelor cuprinsa intre '||v_inf||' si '||v_sup;
WHEN OTHERS THEN
:g_mesaj:='au aparut alte erori';
END;
SET VERIFY ON
PRINT g_mesaj
Activarea unei exceptii externe poate fi facuta si cu ajutorul procedurii RAISE_APPLICATION_ERROR, furnizata de pachetul DBMS_STANDARD.
RAISE_APPLICATION_ERROR poate fi folosita pentru a returna un mesaj de eroare unitatii care o apeleaza, mesaj mai descriptiv (non standard) decat identificatorul erorii. Unitatea apelanta poate fi SQL*Plus, un subprogram PL/SQL sau o aplicatie client.
Procedura are urmatorul antet:
RAISE_APPLICATION_ERROR (numar_eroare IN NUMBER,
mesaj_eroare IN VARCHAR2
Atributul numar_eroare este un numar cuprins intre -20000 si -20999, specificat de utilizator pentru exceptia respectiva, iar mesaj_eroare este un text asociat erorii, care poate avea maximum 2048 octeti.
Parametrul boolean este optional. Daca acest parametru este TRUE, atunci noua eroare se va adauga listei erorilor existente, iar daca este FALSE (valoare implicita) atunci noua eroare va inlocui lista curenta a erorilor (se retine ultimul mesaj de eroare).
O aplicatie poate apela RAISE_APPLICATION_ERROR numai dintr-un subprogram stocat (sau metoda). Daca RAISE_APPLICATION_ERROR este apelata, atunci subprogramul se termina si sunt returnate codul si mesajul asociate erorii respective.
Procedura RAISE_APPLICATION_ERROR poate fi folosita in sectiunea executabila, in sectiunea de tratare a erorilor si chiar simultan in ambele sectiuni.
In sectiunea executabila:
DELETE FROM opera WHERE material = 'carton';
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20201,'info incorecta');
END IF;
In sectiunea de tratare a erorilor:
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20202,'info invalida');
END;
In ambele sectiuni:
DECLARE
e_material EXCEPTION;
PRAGMA EXCEPTION_INIT (e_material, -20777);
BEGIN
DELETE FROM opera WHERE valoare < 100001;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20777,
'nu exista opera cu aceasta valoare');
END IF;
EXCEPTION
WHEN e_material THEN
-- trateaza eroarea aceasta
END;
RAISE_APPLICATION_ERROR faciliteaza comunicatia dintre client si server, transmitand aplicatiei client erori specifice aplicatiei de pe server (de obicei, un declansator). Prin urmare, procedura este doar un mecanism folosit pentru comunicatia server client a unei erori definite de utilizator, care permite ca procesul client sa trateze exceptia.
Exemplu
Sa se implementeze un declansator care nu permite acceptarea in muzeu a operelor de arta avand valoarea mai mica de 100000
CREATE OR REPLACE TRIGGER minim_valoare
BEFORE INSERT ON opera
FOR EACH ROW
BEGIN
IF :NEW.valoare < 100000 THEN
RAISE_APPLICATION_ERROR
(-20005,'operele de arta trebuie sa aiba valoare
mai mare de 100000$');
END IF;
END;
Pe statia client poate fi scris un program care detecteaza si trateaza eroarea.
DECLARE
/* declarare exceptie */
nu_accepta EXCEPTION;
/* asociaza nume,codului eroare folosit in trigger */
PRAGMA EXCEPTION_INIT(nu_accepta,-20005);
BEGIN
/* incearca sa inserezi */
INSERT INTO opera .;
EXCEPTION
/* tratare exceptie */
WHEN nu_accepta THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
/* SQLERRM va returna mesaj din RAISE_APPLICATION_ERROR */
END;
Cazuri speciale in tratarea exceptiilor
Daca se declanseaza o exceptie intr-un bloc simplu, atunci se face saltul la partea de tratare (handler) a acesteia, iar dupa ce este terminata tratarea erorii se iese din bloc (instructiunea END).
Prin urmare, daca exceptia se propaga spre blocul care include blocul curent, restul actiunilor executabile din subbloc sunt "pierdute". Daca dupa o eroare se doreste totusi continuarea prelucrarii datelor, este suficient ca instructiunea care a declansat exceptia sa fie inclusa intr-un subbloc.
Dupa ce subblocul a fost terminat, se continua secventa de instructiuni din blocul principal.
Exemplu
BEGIN
DELETE .
SELECT .--poate declansa exceptia A
--nu poate fi efectuat INSERT care urmeaza
INSERT INTO .
EXCEPTION
WHEN A THEN .
END;
Deficienta anterioara se poate rezolva incluzand intr-un subbloc comanda SELECT care a declansat exceptia.
BEGIN
DELETE .
BEGIN
SELECT .
.
EXCEPTION
WHEN A THEN .
/* dupa ce se trateaza exceptia A, controlul este
transferat blocului de nivel superior, de fapt
comenzii INSERT */
END;
INSERT INTO .
.
EXCEPTION
END;
Uneori este dificil de aflat care comanda SQL a determinat o anumita eroare, deoarece exista o singura sectiune pentru tratarea erorilor unui bloc. Sunt sugerate doua solutii pentru rezolvarea acestei probleme.
Introducerea unui contor care sa identifice instructiunea SQL.
DECLARE
v_sel_cont NUMBER(2):=1;
BEGIN
SELECT .
v_sel_cont:=2;
SELECT .
v_sel_cont:=3;
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_table(info)
VALUES ('comanda SELECT ' || TO_CHAR(v_sel_cont) ||
' nu gaseste date');
END;
Introducerea fiecarei instructiuni SQL intr-un subbloc.
BEGIN
BEGIN
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_table(info)
VALUES('SELECT 1 nu gaseste date');
END;
BEGIN
SELECT .
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO log_table(info)
VALUES('SELECT 2 nu gaseste date');
END;
.
END;
Activarea exceptiilor
Pentru activarea unei exceptii exista doua metode:
activarea explicita a exceptiei (definite de utilizator sau predefinite) in interiorul blocului, cu ajutorul comenzii RAISE;
activarea automata a exceptiei asociate unei erori Oracle.
Exceptiile pot fi sesizate in sectiunea executabila, declarativa sau in cea de tratare a exceptiilor. La aceste niveluri ale programului, o exceptie poate fi gestionata in moduri diferite.
Pentru a reinvoca o exceptie, dupa ce a fost tratata in blocul curent, se foloseste instructiunea RAISE, dar fara a fi insotita de numele exceptiei. In acest fel, dupa executarea instructiunilor corespunzatoare tratarii exceptiei, aceasta se transmite si blocului "parinte". Pentru a fi recunoscuta ca atare de catre blocul "parinte", exceptia trebuie sa nu fie definita in blocul curent, ci in blocul "parinte" (sau chiar mai sus in ierarhie), in caz contrar ea putand fi captata de catre blocul "parinte" doar la categoria OTHERS.
Pentru a executa acelasi set de actiuni in cazul mai multor exceptii nominalizate explicit, in sectiunea de prelucrare a exceptiilor se poate utiliza operatorul OR.
Pentru a evita tratarea fiecarei erori in parte, se foloseste sectiunea WHEN OTHERS care va cuprinde actiuni pentru fiecare exceptie care nu a fost tratata, adica pentru captarea exceptiilor neprevazute sau necunoscute. Aceasta sectiune trebuie utilizata cu atentie deoarece poate masca erori critice sau poate impiedica aplicatia sa raspunda in mod corespunzator.
Propagarea exceptiilor
Daca este declansata o eroare in sectiunea executabila si blocul curent are un handler pentru tratarea ei, atunci blocul se termina cu succes, iar controlul este dat blocului imediat exterior.
Daca se produce o exceptie care nu este tratata in blocul curent, atunci exceptia se propaga spre blocul "parinte", iar blocul PL/SQL curent se termina fara succes. Procesul se repeta pana cand fie se gaseste intr-un bloc modalitatea de tratare a erorii, fie se opreste executia si se semnaleaza situatia aparuta (unhandled exception error).
Daca este declansata o eroare in partea declarativa a blocului, aceasta este propagata catre blocul imediat exterior, chiar daca exista un handler al acesteia in blocul corespunzator sectiunii declarative.
La fel se intampla daca o eroare este declansata in sectiunea de tratare a erorilor. La un moment dat, intr-o sectiune EXCEPTION, poate fi activa numai o singura exceptie.
Instructiunea GOTO nu permite:
saltul la sectiunea de tratare a unei exceptii;
saltul de la sectiunea de tratare a unei exceptii, in blocul curent.
Comanda GOTO permite totusi saltul de la sectiunea de tratare a unei exceptii la un bloc care include blocul curent.
Exemplu
Exemplul urmator marcheaza un salt ilegal in blocul curent.
DECLARE
v_var NUMBER(10,3);
BEGIN
SELECT dim2/NVL(valoare,0)
INTO v_var
FROM opera
WHERE dim1 > 100;
<<eticheta>>
INSERT INTO politaasig(cod_polita, valoare)
VALUES (7531, v_var);
EXCEPTION
WHEN ZERO_DIVIDE THEN v_var:=0;
GOTO <<eticheta>>; --salt ilegal in blocul curent
END;
In continuare, vor fi analizate modalitatile de propagare a exceptiilor in cele trei cazuri comentate: exceptii sesizate in sectiunea declarativa, in sectiunea executabila si in sectiunea de tratare a erorilor.
Exceptie sesizata in sectiunea executabila
Exceptia este sesizata si tratata in subbloc. Dupa aceea, controlul revine blocului exterior.
DECLARE
A EXCEPTION;
BEGIN
.
BEGIN
RAISE A; -- exceptia A sesizata in subbloc
EXCEPTION
WHEN A THEN .-- exceptia tratata in subbloc
.
END;
-- aici este reluat controlul
END;
Exceptia este sesizata in subbloc, dar nu este tratata in acesta si atunci se propaga spre blocul exterior. Regula poate fi aplicata de mai multe ori.
DECLARE
A EXCEPTION;
B EXCEPTION;
BEGIN
BEGIN
RAISE B; --exceptia B sesizata in subbloc
EXCEPTION
WHEN A THEN .
--exceptia B nu este tratata in subbloc
END;
EXCEPTION
WHEN B THEN .
/* exceptia B s-a propagat spre blocul exterior unde a
fost tratata, apoi controlul trece in exteriorul blocului */
END;
Exceptie sesizata in sectiunea declarativa
Daca in sectiunea declarativa este generata o exceptie, atunci aceasta se propaga catre blocul exterior, unde are loc tratarea acesteia. Chiar daca exista un handler pentru exceptie in blocul curent, acesta nu este executat.
Exemplu
Sa se realizeze un program prin care sa se exemplifice propagarea erorilor aparute in sectiunea declarativa a unui bloc PL/SQL.
Programul calculeaza numarul creatorilor de opere de arta care au lucrari expuse in muzeu.
BEGIN
DECLARE
nr_artisti NUMBER(3) := 'XYZ';
BEGIN
SELECT COUNT (DISTINCT cod_autor)
INTO nr_artisti
FROM opera;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Eroare bloc intern:' || SQLERRM);
END;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Eroare bloc extern:' || SQLERRM );
END;
Deoarece la initializarea variabilei nr_artisti apare o neconcordanta intre tipul declarat si cel asignat, este generata eroarea interna VALUE_ERROR. Cum eroarea a aparut in partea declarativa a blocului intern, desi acesta contine un handler OTHERS care ar fi putut capta eroarea, handler-ul nu este executat, eroarea fiind propagata catre blocul extern unde este tratata in handler-ul OTHERS asociat. Aceasta se poate remarca deoarece la executie se obtine mesajul: "Eroare bloc extern: ORA-06502: PL/SQL: numeric or value error".
Exceptie sesizata in sectiunea EXCEPTION
Daca exceptia este sesizata in sectiunea EXCEPTION, ea se propaga imediat spre blocul exterior.
BEGIN
DECLARE
A EXCEPTION;
B EXCEPTION;
BEGIN
RAISE A; --sesizare exceptie A
EXCEPTION
WHEN A THEN
RAISE B; --sesizare exceptie B
WHEN B THEN .
/* exceptia este propagata spre blocul exterior
cu toate ca exista aici un handler pentru ea */
END;
EXCEPTION
WHEN B THEN .
--exceptia B este tratata in blocul exterior
END;
Informatii despre erori
Pentru a obtine textul corespunzator erorilor la compilare, poate fi utilizata vizualizarea USER_ERRORS din dictionarul datelor. Pentru informatii aditionale referitoare la erori pot fi consultate vizualizarile ALL_ERRORS sau DBA_ERRORS.
Vizualizarea USER_ERRORS are campurile:
NAME (numele obiectului),
TYPE (tipul obiectului),
SEQUENCE (numarul secventei),
LINE (numarul liniei din codul sursa in care a aparut eroarea),
POSITION (pozitia in linie unde a aparut eroarea),
TEXT (mesajul asociat erorii).
Exemplu
Sa se afiseze erorile de compilare din procedura alfa.
SELECT LINE, POSITION, TEXT
FROM USER_ERRORS
WHERE NAME = 'ALFA';
LINE specifica numarul liniei in care apare eroarea, dar acesta nu corespunde liniei efective din fisierul text (se refera la codul sursa depus in USER_SOURCE).
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 1577
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved