BAZY DANYCH W APLIKACJACH SIECIOWYCH Wykład 4 Wyjątki. Wyzwalacze bazodanowe. (Wybrane materiały) Dr inż. E. Busłowska Obsługa wyjątków w PLSQL Wyjątek (ang. Exception) - błąd lub ostrzeżenie w PLSQL Typy wyjątków: 1. Systemowe (predefiniowane) dzielenie przez zero brak wolnej pamięci brak praw do obiektu 2. Definiowane przez użytkownika za niskie zarobki za wysoka wartość zamówienia zbyt mała ilość książek 1 2 Kontrola obsługi wyjątku a NUMBER := 0; Obsługa wyjątków w PLSQL b NUMBER := 0; Wystąpienie błędu jest sygnalizowane przez wywołanie wyjątku. Błędy systemowe sygnalizowane są automatycznie Błędy definiowane przez użytkownika są wywoływane ręcznie za pomocą polecenia RAISE. Po wystąpieniu wyjątku kontrola przechodzi do procedury obsługi wyjątku (ang. exception handler). c NUMBER; a := 20; c := a b; WHEN NO_DATA_FOUND THEN INSERT INTO komunikat VALUES ( Brak danych, SYSDATE); Po jej wykonaniu kontrola przechodzi do kolejnego bloku nadrzędnego. SELECT ilosc INTO a FROM t_ksiazka; Jeśli procedura obsługi danego błędu nie zostanie znaleziona, to wykonywanie programu zostanie przerwane. WHEN ZERO_DIVIDE THEN INSERT INTO komunikat VALUES ( Dzielenie przez 0, SYSDATE); WHEN OTHERS THEN INSERT INTO komunikat VALUES ( Inny błąd, SYSDATE); 3 4 Wyjątki predefiniowane CURSOR_ALREADY_OPEN - wywoływany w przypadku próby otwarcia kursora już otwartego; DUP_VAL_ON_INDEX - wywoływany w przypadku próby wykonania rozkazu INSERT lub UPDATE, który spowodowałby utworzenie dwóch takich samych wierszy w indeksie zadeklarowanym jako UNIQUE; INVALID_CURSOR - wywoływany w przypadku próby dostępu do nieprawidłowego kursora (np. nie otwartego); INVALID_NUMBER - wywoływany w przypadku próby wykonania konwersji do typu numerycznego z tekstu, który nie reprezentuje liczby; NO_DATA_FOUND - wywoływany wtedy, gdy rozkaz SELECT powinien zwrócić jeden wiersz a nie zwraca żadnego (np. SELECT INTO); STORAGE_ERROR - wywoływany w przypadku braku wolnej pamięci lub uszkodzenia zawartości pamięci; TOO_MANY_ROWS - wywoływany w przypadku, gdy rozkaz SELECT zwraca więcej niż jeden wiersz, a oczekiwany jest tylko jeden (np. SELECT INTO); VALUE_ERROR - wywoływany w przypadku przypisania złej wartości do zmiennej lub pola; ZERO_DIVIDE - próba dzielenia przez zero; Budowa modułu obsługi wyjątków WHEN wyjątek1 THEN instrukcje [WHEN wyjątek2 THEN instrukcje ] [WHEN OTHERS THEN instrukcje ] 5 6 1
Przypisania tej samej akcji różnym wyjątkom Nazwy tych wyjątków wypisać w klauzuli WHEN oddzielając słowem OR: WHEN dane1 OR dane2 OR VALUE_ERROR THEN Nie można jednak użyć słowa OTHERS w takiej liście. Słowo OTHERS zawsze musi wystąpić oddzielnie. Należy pamiętać również, że dla jednego wyjątku może być zdefiniowana tylko jedna funkcja obsługi w danym bloku. W funkcjach obsługi wyjątków mają zastosowanie normalne reguły przesłaniania tzn. widoczne są tylko zmienne globalne lub lokalne. Definiowanie własnych wyjątków ; BRAK_DANYCH ; 7 8 Definiowanie własnych wyjątków Wywoływanie zdefiniowanych wyjątków przed użyciem wyjątek musi być zadeklarowany deklarowane w blokach deklaracji dowolnych bloków PLSQL wyjątek jest widoczny w danym bloku i wszystkich jego blokach podrzędnych wyjątek w języku PLSQL nie jest obiektem ale informacją o spełnieniu pewnych określonych warunków do wyjątku nie można przypisać żadnej wartości ani użyć wyjątku w jakiejkolwiek operacji arytmetycznej. wyjątek nie może być również używany w rozkazach SQL. nie jest możliwa deklaracja tego samego wyjątku dwa razy w tym samym bloku. Można jednak zadeklarować ten sam wyjątek w różnych blokach. wyjątki predefiniowane wywoływane są przez system automatycznie. wyjątki zdefiniowane przez użytkownika, muszą być przez niego wywołane v_l NUMBER := 0; v_isbn NUMBER := &isbn; ex_za_malo_ksiazek ; SELECT ilosc INTO v_l FROM t_ksiazka WHERE ISBN = v_isbn; IF (v_l < 3) THEN RAISE ex_za_malo_ksiazek; WHEN ex_za_malo_ksiazek THEN DBMS_OUTPUT.PUT_LINE('KSIĄŻEK O ISBN ' v_isbn ' JEST MNIEJ NIŻ 3!'); 9 10 Propagacja wyjątków Wywoływanie predefiniowanych wyjątków A Exception; B Exception; C Exception; RAISE C; WHEN A THEN WHEN A THEN Wyjątek C jest propagowany do bloku obejmującego, gdzie również nie ma żadnego programu obsługi tego wyjątku Użytkownik może wywoływać ręcznie zarówno błędy systemowe, jak i zdefiniowane przez siebie. Każdy wywołany błąd powinien zostać obsłużony przez odpowiednią procedurę obsługi wyjątku. Możliwe jest również jawne (za pomocą rozkazu RAISE) wywoływanie predefiniowanych wyjątków: RAISE INVALID_NUMBER; Czasami istnieje konieczność powtórnego wywołania wyjątku z funkcji, która go obsługuje, w celu przekazania go do bloku nadrzędnego. em może tu być wycofanie transakcji w bloku zagnieżdżonym i zgłoszenie informacji o błędzie w bloku nadrzędnym. W związku z tym możliwe jest użycie rozkazu RAISE w funkcji obsługi wyjątku. Należy pamiętać, że wyjątki zgłoszone w funkcji obsługi innego wyjątku są zawsze przekazywane do bloku nadrzędnego i tam wyszukiwana jest odpowiednia funkcja obsługi zgodnie z zasadami opisanymi wcześniej. Podobnie wyjątki zgłaszane w części deklaracyjnej przekazywane są do bloku nadrzędnego i tam podlegają przetwarzaniu. 11 12 2
Funkcje SQLCODE i SQLERRM Procedura RAISE_APPLICATION_ERROR Funkcja SQLCODE zwraca numer błędu, który wystąpił. Numer jest zawsze ujemny, za wyjątkiem błędu NO_DATA_FOUND (+100) i błędów definiowanych przez użytkownika (+1) Funkcja SQLERRM zwraca treść błędu, który wystąpił. Jeśli nie wystąpił żaden błąd to SQLCODE zwraca 0 a SQLERRM zwraca : ORA-0000: normal, successful completion err_num NUMBER; err_msg VARCHAR2(100); WHEN OTHERS THEN err_num := SQLCODE; err_msg := SUBSTR(SQLERRM, 1, 200); INSERT INTO errors VALUES (err_num, err_msg); Pozwala użytkownikowi określić błąd aplikacji, przypisać mu kod SQLCODE z przedziału 20000 20999 oraz wygenerować niestandardowy komunikat błędu RAISE_APPLICATION_ERROR(numer_błędu, komunikat, [, TRUE FALSE ] ) numer_błędu - liczba ujemna z przedziału <20000 20999> komunikat - łańcuch znaków o rozmiarze do 2048 bajtów TRUE, FALSE: czy błąd ma być umieszczony na szczycie stosu błędów, czy też ma je zastąpić FOR ks_re IN ( SELECT * FROM t_ksiazka ) LOOP IF (ks_re.cena < 25 ) THEN RAISE_APPLICATION_ERROR(-20101, 'Uwaga, tania ksiazka!!!'); ELSE DBMS_OUTPUT.PUT_LINE('Cena ksiażki: ' ks_re.cena); END LOOP; END ; 13 14 Składnia wyzwalacza bazy danych Możliwe typy wyzwalaczy CREATE [OR REPLACE] TRIGGER nazwa_wyzwalacza {BEFORE AFTER} zdarzenie_wywołujące ON nazwa_tabeli [REFERENCING {NEW AS OLD AS} nazwa_kwalifikatora] [] [WHEN (wyrażenie)] [ Opcjonalna sekcja deklaracji zawiera wszystkie lokalne typy, zmienne, stałe, kursory i deklaracje podprogramów] Sekcja poleceń wyzwalacza [ Opcjonalna sekcja wyjątków służąca do obsługi błędów] 15 BEFORE INSERT BEFORE INSERT AFTER INSERT AFTER INSERT BEFORE UPDATE BEFORE UPDATE AFTER UPDATE AFTER UPDATE BEFORE DELETE BEFORE DELETE AFTER DELETE AFTER DELETE 16 Kolejność wykonywania wyzwalaczy CREATE OR REPLACE TRIGGER trig_stanow BEFORE UPDATE OF idstanowiska ON Stanowiska UPDATE Pracownicy SET idstanowiska = 3 WHERE idstanowiska = 6; 1. Wyzwalacz przed instrukcją; 2. Wyzwalacz przed pierwszym wierszem, na którym operuje instrukcja 3. Wyzwalacz po pierwszym wierszu, na którym operuje instrukcja 4. Wyzwalacz przed ostatnim wierszem 5. Wyzwalacz po ostatnim wierszu 6. Wyzwalacz po instrukcji 17 18 3
Odróżnianie wartości w wierszu 1. : OLD - wiersz przed zmianą 2. : NEW - wiersz po zmianie Na przykład: IF :NEW.wartość < :OLD.wartość CREATE OR REPLACE TRIGGER trig_klienci BEFORE UPDATE OF idklienta ON Klienci UPDATE umowy SET idklienta = :new.idklienta WHERE idklienta = :old.idklienta; 19 20 Zmienne systemowe informujące o typie operacji INSERTING - wyzwalacz uruchomiony dla INSERT DELETING - wyzwalacz uruchomiony dla DELETE UPDATING[(kol,)] - wyzwalacz uruchomiony dla UPDATE [i kolumny kol,] 21 CREATE OR REPLACE TRIGGER US_KAS_WP_MOD BEFORE DELETE OR UPDATE OR INSERT ON KLIENT IF DELETING THEN DELETE FROM ODDZIAL WHERE KL_NO= :OLD.KL_NO; ELSIF UPDATING THEN UPDATE ODDZIAL SET KL_NO = :NEW.KL_NO WHERE KL_NO= :OLD.KL_NO; ELSIF INSERTING THEN DBMS_OUTPUT.PUT_LINE('NOWA WARTOSC NAZWISKA:' :NEW.KL_NAZ); 22 Operacje na wyzwalaczach włączaniewyłączanie wyzwalacza ALTER TRIGGER nazwa_wyzwalacza [ENABLE DISABLE] Usuwanie wyzwalacza DROP TRIGGER nazwa_wyzwalacza Perspektywa User_triggers SELECT Trigger_type, Table_name, Triggering_event FROM User_triggers WHERE Trigger_name = 'WYZWALACZ'; lub SELECT Trigger_body FROM User_triggers WHERE Trigger_name = 'WYZWALACZ'; 23 24 4
Wyzwalacz INSTEAD OF Wyzwalacze systemowe CREATE OR REPLACE TRIGGER TRIG_P_DOSTAW INSTEAD OF INSERT ON P_DOSTAWCA V_dost dostawca.id_dostawcy%type; SELECT ID_dostawcy INTO V_dost FROM dostawca WHERE NAZWA =:NEW.NAZWA; INSERT INTO KSIAZKA (ISBN,TYTUL,dostawca) VALUES (:NEW.ISBN,:NEW.TYTUL,V_dost); BEFORE LOGON BEFORE CREATE BEFORE ALTER BEFORE DROP BEFORE AUDIT BEFORE NOAUDIT BEFORE DDL BEFORE GRANT BEFORE RENAME BEFORE REVOKE AFTER LOGON AFTER CREATE AFTER ALTER AFTER DROP AFTER AUDIT AFTER NOAUDIT AFTER DDL AFTER GRANT AFTER RENAME AFTER REVOKE 25 26 5