A PL/SQL programozási nyelv

Kivételkezelés

Szintaxis

A PL/SQL rendelkezik kivételkezelést támogató eszközökkel. A nyelv kivételkezelése blokk-szintű. Vagyis utasításblokkokhoz rendelhetünk kivételkezelő eljárásokat úgy, hogy a blokk végén az EXCEPTION kulcsszó után WHEN ágakban felsoroljuk a kezelni kívánt kivételeket, majd a THEN kulcsszó után leírjuk a végrehajtandó utasításokat. Több ilyen WHEN ágat is létrehozhatunk, különböző kivételek lekezelésére (egy WHEN ágban OR-al “elválasztva” több kivétel is megadható), a végén pedig egy WHEN OTHERS ágat is megadhatunk.
Egy kivételt a RAISE utasítás segítségével válthatunk ki.

Példa:

PROCEDURE Main_feltolt (l_sorszam number) IS BEGIN SELECT u.nev INTO :main.item FROM ugyfel u, WHERE u.sorszam = l_sorszam; EXCEPTION WHEN NO_DATA_FOUND THEN :main.item:=null; END;

PL/SQL-ben a kivételeknek két típusa létezik. Név szerint, a kivételek lehetnek belsők, illetve felhasználó által definiáltak. A belső kivételek a rendszer megfelelő műveleteihez vannak hozzárendelve és alapállapotban legnagyobb részük nem rendelkezik névvel. Szerencsére van néhány belső kivétel, amelyhez - a munka megkönnyítése érdekében - a rendszer társít nevet (a NO_DATA_FOUND is ilyen), de a többi, nem nevesített kivételhez is rendelhetünk nevet az EXCEPTION_INIT pragma segítségével.

Használata:

PRAGMA EXCEPTION_INIT(kivétel_név, Oracle_hibakód);

Az EXCEPTION_INIT pragmát (mint a legtöbb pragmát) a DECLARE szekcióban kell alkalmaznunk. Az utasítás csak abban az esetben működik, ha a kivétel név előzőleg már deklarálva lett.

A nem nevesített belső kivételeket csak a kivételkezelő rész OTHERS ágában tudjuk kezelni.

Kivételek definiálása

Természetesen mi is definiálhatunk kivételeket az EXCEPTION kulcsszó segítségével. Fontos megjegyzés, hogy az EXCEPTION nem típus, csupán egy kulcsszó, amellyel kivételeket deklarálhatunk. Az általunk deklarált kivételek gyakorlatilag csak egy névnek számítanak, amelyet használhatunk kivételek kiváltására, de akár hozzárendelhetünk egy belső hibakódhoz is.

Az előre definiált kivételek a STANDARD package-ben vannak deklarálva az alábbi módon.

CURSOR_ALREADY_OPEN exception; pragma EXCEPTION_INIT(CURSOR_ALREADY_OPEN, '-6511');

A legfontosabb előre definiált kivételek a következők:

A fentieket a következő utasítással listázhatjuk ki:

SELECT text FROM dba_source WHERE type = 'PACKAGE' AND name = 'STANDARD' AND text LIKE '%exception%';

Példa:

DECLARE deadlock_detected EXCEPTION; PRAGMA EXCEPTION_INIT(deadlock_detected, -60); BEGIN ... EXCEPTION WHEN deadlock_detected THEN ... END;

Kivételek kiváltása

A rendszer fenntart egy intervallumot (-20000..-20999) a felhasználó által kiváltott, illetve definiált hibák számára. Ezzel a technikával mi is kiválthatunk nem nevesített kivételeket. Ezt a RAISE_APPLICATION_ERROR eljárással tehetjük meg.

Használata:

raise_application_error(hibakód, hibaüzenet[, {TRUE | FALSE}]);

A RAISE_APPLICATION_ERROR-t csak alprogramban hívhatjuk, meghívásakor azonnal befejeződik az alprogram futása és a vezérlés visszatér a hívó programhoz a megfelelő hibakóddal, amelyet kivételként lekezelhetünk.

Nevesített kivételek kiváltására a RAISE utasítás használható.

Kivételek kezelése

Alprogramok hibáinak lekezelése:
A DBMS_STANDARD package raise_application_error(hibakód, hibaüzenet) procedúrájával az alprogramokból úgy térhetünk vissza, hogy egy megfelelő hibakódot adunk vissza a hívónak, amit az lekezelhet, ha a deklarációjában adott neki egy nevet. (A megadható hibakódok -20000 és -20999 között kell hogy legyenek.) Enélkül csak a WHEN OTHERS résszel tudnánk lekezelni az alprogram hibáit, és így nem tudnánk megállapítani a hiba fajtáját.

A WHEN OTHERS ágban használható pszeudóváltozók:
SQLCODE: kiírathatjuk a kivétel kódját
SQLERRM: kiírathatjuk a hibát

Kivételek terjedése

Ha a végrehajtási rész futásában kivétel vagy run-time hiba lép fel, akkor a futtató rendszer az adott blokkbeli rész exception részében kezdi keresni a kezelését. Ha nem találja, akkor a befoglaló blokk exception részében keresi, és így tovább felfelé haladva terjed… Ha azonban a deklarációs részben történik hiba, akkor egyből a befogadó blokk exception részében kezdi keresni a kezelést. Ha az exception részben lép fel hiba, akkor a deklarációs részben fellépő hiba kezeléséhez hasonló ennek is a kezelése. Ez alól azonban kivétel: ha egy BEGIN … END blokkot készítünk az exception részben, és ott kezeljük, a blokkon belül, egy másik exception részben.