SELECT INTO
7. fejezet - Kivételkezelés
Egy PL/SQL programban a kivételek események. A kivételek rendszere a PL/SQL-ben a futás közben bekövetkező események (kiemelt módon a hibák) kezelését teszi lehetővé. A kivételek lehetnek beépített kivételek (amelyeket általában a futtató rendszer vált ki), vagy felhasználói kivételek, amelyeket valamelyik programegység deklarációs részében határoztunk meg. A beépített kivételeknek lehet nevük (például ZERO_DIVIDE), a felhasználói kivételeknek mindig van nevük. A felhasználói kivételeket mindig explicit módon, külön utasítással kell kiváltani. Ezzel az utasítással beépített kivétel is kiváltható.
A kivételek kezelésére a programegységekbe kivételkezelőt építhetünk be.
Egy kivételhez a PL/SQL-ben egy kód és egy üzenet tartozik. A beépített üzenetek kódja (egyetlen esettől eltekintve) negatív, a felhasználói kivételeké pozitív.
A beépített kivételeket a STANDARD csomag definiálja. A megnevezett beépített kivételek és a hozzájuk tartozó, az Oracle-rendszer által adott hibaüzenetek (ezek nyelve az NLS beállításoktól függ) a 7.1. táblázatban láthatók. A 7.2. táblázat ismerteti a beépített kivételek tipikus kiváltó okait.
7.1. táblázat - Hibaüzenetek
Kivétel Hibakód
SQLCOD E
Hibaüzenet SQLERRM
ACCESS_INTO_NULL -6530 ORA-06530: Incializálatlan összetett objektumra való hivatkozás
CASE_NOT_FOUND -6592 ORA-06592: CASE nem található a CASE állítás végrehajtásakor
COLLECTION_IS_NUL L
-6531 ORA-06531: Inicializálatlan gyűjtőre való hivatkozás
CURSOR_ALREADY_O PEN
-6511 ORA-06511: PL/SQL: A kurzor már meg van nyitva
DUP_VAL_ON_INDEX -1 ORA-00001: A(z) (.) egyediségre vonatkozó megszorítás nem teljesül
INVALID_CURSOR -1001 ORA-01001: Nem megengedett kurzor INVALID_NUMBER -1722 ORA-01722: Nem megengedett szám
LOGIN_DENIED -1017 ORA-01017: Nem megengedett
felhasználónév/jelszó; a bejelentkezés visszautasítva
NO_DATA_FOUND 100 ORA-01403: Nem talált adatot NOT_LOGGED_ON -1012 ORA-01012: Nincs bejelentkezve PROGRAM_ERROR –6501 ORA-06501: PL/SQL: programhiba
ROWTYPE_MISMATC -6504 ORA-06504: PL/SQL: Az Eredmény halmaz
Kivételkezelés
H változói vagy a kérdés visszaadott típusai nem
illeszkednek
SELF_IS_NULL -30625 ORA-30625: A metódus használata nem engedélyezett NULL SELF argumentummal STORAGE_ERROR -6500 ORA-06500: PL/SQL: tárolási hiba
SUBSCRIPT_BEYOND_
COUNT
-6533 ORA-06533: Számlálón kívüli indexérték
SUBSCRIPT_OUTSIDE_
LIMIT
-6532 ORA-06532: Határon kívüli index
SYS_INVALID_ROWID -1410 ORA-01410: Nem megengedett ROWID
TIMEOUT_ON_RESOU RCE
-51 ORA-00051: Időtúllépés történt erőforrásra várakozás közben
TOO_MANY_ROWS -1422 ORA-01422: A pontos lehívás (FETCH) a kívántnál több sorral tér vissza
VALUE_ERROR -6502 ORA-06502: PL/SQL: numerikus- vagy
értékhiba
ZERO_DIVIDE -1476 ORA-01476: Az osztó értéke nulla
7.2. táblázat - Beépített kivételek tipikus kiváltó okai
Kivétel Kiváltódik, ha …
ACCESS_INTO_NULL Megpróbál értéket adni egy inicializálatlan (automatikusan NULL) objektum attribútumának.
CASE_NOT_FOUND A CASE utasítás egyetlen WHEN ága sem egyezik meg a feltétellel és nincs ELSE ág.
COLLECTION_IS_NUL L
Megpróbál hivatkozni egy EXISTS-től különböző kollekciómetódusra egy inicializálatlan (automatikusan NULL) beágyazott tábla vagy dinamikus tömb esetén, vagy megpróbál értéket adni egy inicializálatlan beágyazott tábla vagy dinamikus tömb elemének.
CURSOR_ALREADY_O PEN
Megpróbál újra megnyitni egy már megnyitott kurzort. A kurzorokat le kell zárni, mielőtt újra megnyitjuk. A kurzor FOR ciklusa automatikusan megnyitja a hozzárendelt kurzort, így azt a ciklusban nem lehet újra megnyitni.
DUP_VAL_ON_INDEX Már létező értéket próbál meg tárolni egy adatbázistábla olyan oszlopában, amelyen egyedi (UNIQUE) indexmegszorítás van.
INVALID_CURSOR Megpróbál műveletet végezni egy meg nem nyitott kurzoron.
Kivételkezelés
INVALID_NUMBER SQL utasításban sikertelen egy karakterlánc konverziója, mert annak tartalma ténylegesen nem egy számot reprezentál. (A procedurális utasításokban ilyen konverziós hiba esetén VALUE_ERROR kivétel váltódik ki.) Ez a kivétel váltódik ki akkor is, ha a LIMIT előírás nem pozitív számot eredményez egy együttes hozzárendelést tartalmazó FETCH utasításban.
LOGIN_DENIED Bejelentkezéskor hibás a felhasználónév vagy a jelszó.
NO_DATA_FOUND Egy SELECT INTO utasítás nem ad vissza sorokat, vagy a programban hivatkozik egy beágyazott tábla törölt, vagy egy asszociatív tömb inicializálatlan elemére. Az SQL csoportfüggvényei, például AVG, SUM, mindig adnak vissza értéket vagy NULL-t, ezért csoportfüggvényt tartalmazó SELECT INTO utasítás sohasem váltja ki ezt a kivételt.
NOT_LOGGED_ON Megpróbál adatbázis-műveletet végrehajtani úgy, hogy nem kapcsolódik Oracle-példányhoz.
PROGRAM_ERROR PL/SQL belső hiba.
ROWTYPE_MISMATC H
Egy értékadásban a kurzor gazdaváltozó és az értékül adandó PL/SQL kurzor visszatérési típusa nem kompatibilis.
Például abban az esetben, ha egy már megnyitott kurzorváltozót adunk át egy alprogramnak, akkor a formális és aktuális paraméterek visszatérési típusának kompatibilisnek kell lennie. Ugyanígy előfordulhat, hogy egy megnyitott gyenge kurzorváltozót adunk értékül egy erős kurzorváltozónak, és azok visszatérési típusa nem kompatibilis.
SELF_IS_NULL Megpróbálja egy NULL referenciájú objektum metódusát meghívni, azaz a rögzített SELF paraméter (ami minden metódus első paramétere) NULL.
STORAGE_ERROR Elfogyott a PL/SQL számára rendelkezésre álló memória, vagy a memóriaterület megsérült.
SUBSCRIPT_BEYOND_
COUNT
Egy beágyazott tábla vagy dinamikus tömb méreténél nagyobb indexű elemére hivatkozik.
SUBSCRIPT_OUTSIDE_
LIMIT
Egy beágyazott tábla vagy dinamikus tömb elemére hivatkozik egy olyan indexszel, ami nincs a megengedett tartományban (például –1).
SYS_INVALID_ROWID Sikertelen egy karakterlánc konverziója ROWID típussá, mert a karakterlánc ténylegesen nem egy ROWID értéket
TOO_MANY_ROWS Egy SELECT INTO utasítás egynél több sort ad vissza.
Kivételkezelés
VALUE_ERROR Aritmetikai, konverziós, csonkítási vagy hosszmegszorítási hiba történik. Például ha egy sztring változónak a deklarált maximális hosszánál hosszabb sztringet próbál meg értékül adni, akár egy SELECT INTO utasítással. Ilyenkor az értékadás érvénytelen, semmis lesz és VALUE_ERROR kivétel váltódik ki. Procedurális utasítások esetén akkor is ez a kivétel váltódik ki, ha egy sztring konverziója számmá sikertelen (SQL utasításokban ilyenkor INVALID_NUMBER kivétel váltódik ki).
ZERO_DIVIDE Megpróbál nullával osztani.
Felhasználói kivételeket a EXCEPTION alapszóval deklarálhatunk:
DECLARE
sajat_kivetel EXCEPTION;
Olyan beépített kivételhez, amely eredetileg nincs nevesítve, egy pragma segítségével a programunkban nevet rendelhetünk egy programegység deklarációs részében. Ekkor deklarálnunk kell egy felhasználói kivételnevet, majd ugyanezen deklarációs részben később alkalmazni rá a pragmát. Ezután az adott beépített kivételt név szerint tudjuk kezelni. A pragma alakja:
PRAGMA EXCEPTION_INIT(kivételnév,kód);
1. példa DECLARE
i PLS_INTEGER;
j NUMBER NOT NULL := 1;
/* Egy névtelen hiba nevesítése. */
numeric_overflow EXCEPTION;
PRAGMA EXCEPTION_INIT(numeric_overflow, -1426); -- numeric overflow /* Egy már amúgy is nevesített kivételhez még egy név rendelése. */
VE_szinonima EXCEPTION;
PRAGMA EXCEPTION_INIT(VE_szinonima, -6502); -- VALUE_ERROR BEGIN
/* Kezeljük a numeric overflow hibát, PL/SQL-ben ehhez a hibához nincs előre definiálva kivételnév. */
<<blokk1>>
BEGIN i := 2**32;
EXCEPTION
WHEN numeric_overflow THEN
DBMS_OUTPUT.PUT_LINE('Blokk1 - numeric_overflow!' || SQLERRM);
END blokk1;
/* A VE_szinonima használható VALUE_ERROR helyett. */
Kivételkezelés
<<blokk2>>
BEGIN i := NULL;
j := i; -- VALUE_ERROR-t vált ki, mert i NULL.
DBMS_OUTPUT.PUT_LINE(j);
EXCEPTION
WHEN VE_szinonima THEN
DBMS_OUTPUT.PUT_LINE('Blokk2 - VALUE_ERROR: ' || SQLERRM);
END blokk2;
/* A VALUE_ERROR is használható VE_szinonima helyett. A két kivétel megegyezik. */
<<blokk2>>
BEGIN
RAISE VE_szinonima;
EXCEPTION
WHEN VALUE_ERROR THEN -- A saját kivételünk szinonima a VALUE_ERROR-ra DBMS_OUTPUT.PUT_LINE('Blokk3 - VALUE_ERROR: ' || SQLERRM);
END blokk1;
END;
/ /*
Eredmény:
Blokk1 - numeric_overflow!ORA-01426: numerikus túlcsordulás
Blokk2 - VALUE_ERROR: ORA-06502: PL/SQL: numerikus- vagy értékhiba () Blokk3 - VALUE_ERROR: ORA-06502: PL/SQL: numerikus- vagy értékhiba () A PL/SQL eljárás sikeresen befejeződött.
*/
Bármely megnevezett kivétel kiváltható a következő utasítással:
RAISE kivételnév;
Az utasítás bárhol elhelyezhető, ahol végrehajtható utasítás szerepelhet.
Kivételkezelő bármely programegység végén az EXCEPTION alapszó után helyezhető el. Felépítése a következő:
WHEN kivételnév [OR kivételnév]…
THEN utasítás [utasítás]…
[WHEN kivételnév [OR kivételnév]…
THEN utasítás [utasítás]…]…
Kivételkezelés
[WHEN OTHERS THEN utasítás [utasítás]…]
A kivételkezelő tehát olyan WHEN ágakból áll, amelyek név szerint kezelik a kivételeket és legutolsó ágként szerepelhet egy OTHERS ág, amely minden kivételt kezel.
Ha egy blokkban vagy alprogramban a végrehajtható részben bekövetkezik egy kivétel, akkor a végrehajtható rész futása félbeszakad és a futtató rendszer megvizsgálja, hogy a blokk vagy alprogram tartalmaz-e kivételkezelőt. Ha igen, megnézi, hogy valamelyik WHEN ágban nevesítve van-e a bekövetkezett kivétel. Ha igen, akkor végrehajtódnak a THEN után megadott utasítások. Ha köztük van GOTO, akkor a megadott címkén, ha nincs GOTO, blokk esetén a blokkot követő utasításon (ha van tartalmazó programegység) folytatódik a futás, egyébként pedig a vezérlés visszaadódik a hívási környezetbe. Az a programegység, amelyben egy kivétel bekövetkezik, inaktívvá válik, tehát futása nem folytatható. Így GOTO-val sem lehet visszatérni azon végrehajtható részre, ahol a kivétel bekövetkezett.
2. példa DECLARE
a NUMBER NOT NULL := 1;
b NUMBER;