PL/SQL v příkladech / Výjimky

Jak již bylo naznačeno v úvodu, pro zachytávání chyb běhu programu slouží část bloku uvozená klíčovým slovem EXCEPTION. Rozlišujeme chyby systémové, které jsou vyvolány automaticky při výskytu chyby, a uživatelsky definované, které je nutné vyvolat explicitně příkazem RAISE. Několik nejčastějších systémových popisují následující příklady.

Systémové

VALUE_ERROR

DECLARE
  l_Cislo NUMBER;
BEGIN
  l_Cislo:='Franta';
EXCEPTION
  WHEN VALUE_ERROR THEN
    dbms_output.put_line('Selhala implicitní konverze!');
END;

ZERO_DIVIDE

DECLARE
  l_Cislo NUMBER;
BEGIN
  l_Cislo:=20/0;
EXCEPTION
  WHEN ZERO_DIVIDE THEN
    dbms_output.put_line('Dělení nulou!');
END;

NO_DATA_FOUND

DECLARE
  l_Cislo NUMBER;
BEGIN
  SELECT employee_id
    INTO l_Cislo
    FROM employees
    WHERE (last_name='Vomacka')
  ;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    dbms_output.put_line('Zaměstnanec Vomacka neexistuje!');
END;

TOO_MANY_ROWS

DECLARE
  l_Cislo NUMBER;
BEGIN
  SELECT employee_id
    INTO l_Cislo
    FROM employees
    WHERE (salary>3000)
  ;
EXCEPTION
  WHEN TOO_MANY_ROWS THEN
    dbms_output.put_line('Víc než jeden řádek!');
END;

COLLECTION_IS_NULL

CREATE OR REPLACE TYPE Varchar_TT IS TABLE OF VARCHAR2(4000);
/
DECLARE
  lt_Pole Varchar_TT;
BEGIN
  --lt_Pole:=Varchar_TT();
  --lt_Pole.EXTEND(1);
  lt_Pole(1):='test';
EXCEPTION
  WHEN COLLECTION_IS_NULL THEN
    dbms_output.put_line('Neinicializovaný objekt!');
END;

SUBSCRIPT_BEYOND_COUNT

DECLARE
  lt_Pole Varchar_TT;
  l_Cnt NUMBER;
BEGIN
  lt_Pole:=Varchar_TT();
  lt_Pole.EXTEND(1);
  lt_Pole(2):='test';
EXCEPTION
  WHEN SUBSCRIPT_BEYOND_COUNT THEN
    dbms_output.put_line('Mimo index pole!');
END;

OTHERS

V jednom bloku je možné odchytit více typů chyb, nicméně platí, že pokud chyba nemá svůj handler, program skončí v obecné výjimce OTHERS. Zprávu o mimořádné události vrací funkce SQLERRM.

DECLARE
  lt_Pole Varchar_TT;
BEGIN
  lt_Pole:=Varchar_TT();
  lt_Pole.EXTEND(1);
  lt_Pole(2):='test';
EXCEPTION
  WHEN COLLECTION_IS_NULL THEN
    dbms_output.put_line('Neinicializovaný objekt!');
  WHEN OTHERS THEN
    dbms_output.put_line(SQLERRM); -- ORA-06533: Subscript beyond count
END;

V situacích, kdy dopředu víme, že bude operace potenciálně nebezpečná, je dobrou praxí chybám spíše předcházet. Ve velmi rozsáhlých systémech to zjednodušuje následné hledání problému.

DECLARE
  l_NebezpecneCislo NUMBER:=0;
  l_Pocet PLS_INTEGER;
  l_Vysledek NUMBER;
BEGIN
  -- ošetření NO_DATA_FOUND a TOO_MANY_ROWS
  SELECT COUNT(1)
    INTO l_Pocet
    FROM employees
    WHERE (last_name='Russell')
  ;
  IF    (l_Pocet>0)
    AND (l_Pocet<2)
  THEN
    -- existuje právě jeden
    SELECT CASE -- ošetření ZERO_DIVIDE a NULL hodnoty
             WHEN (NVL(l_NebezpecneCislo, 0)=0)
               THEN 0
             ELSE (salary/l_NebezpecneCislo)
           END
      INTO l_Vysledek
      FROM employees
      WHERE (last_name='Russell')
    ;
    dbms_output.put_line(l_Vysledek);
  ELSE
    -- neexistuje nebo jich je víc
    dbms_output.put_line('Počet zaměstnanců: '||l_Pocet);
  END IF;
EXCEPTION
  WHEN OTHERS THEN
    dbms_output.put_line('Neznámá chyba!');
END;

Uživatelské

Pokud nám předpřipravené Oracle výjimky nestačí, na řadě je definice vlastních v deklarativní části anonymního bloku nebo package. Pro vyvolání uživatelské výjimky slouží příkaz RAISE.

DECLARE
  VYJIMKA EXCEPTION;
BEGIN
  -- potenciálně
  -- nebezpečné
  -- operace
  RAISE VYJIMKA;
EXCEPTION
  WHEN VYJIMKA THEN
    dbms_output.put_line('Moje výjimka');
END;

Propagace výjimek

Další příklad vysvětluje systém zachytávání a propagace výjimek skrze několik úrovní bloků kódu. V tomto případě jsou výjimky deklarované v samostatném balíku.

CREATE OR REPLACE PACKAGE BalikVyjimek
AS
  VNEJSI_VYJIMKA EXCEPTION;
  VNITRNI_VYJIMKA EXCEPTION;
END;
/
BEGIN
  /* ZAČÁTEK VNITŘNÍHO BLOKU */
  BEGIN
    -- potenciálně
    -- nebezpečné
    -- operace
    RAISE BalikVyjimek.VNITRNI_VYJIMKA;
  EXCEPTION
    WHEN BalikVyjimek.VNITRNI_VYJIMKA THEN
      dbms_output.put_line('Vnitřní výjimka');
  END;
  /* KONEC VNITŘNÍHO BLOKU */
  -- vnitřní výjimka byla odchycena, pokračuji
  -- další
  -- nebezpečnou
  -- operací
  RAISE BalikVyjimek.VNEJSI_VYJIMKA;
EXCEPTION
  -- VNEJSI_VYJIMKA nemá svůj handler, program skončí v obecné
  WHEN OTHERS THEN
    dbms_output.put_line('Jiná neočekávaná chyba');
END;

Zanechte komentář

Vaše emailová adresa nebude zobrazena. Povinná pole jsou označena *