1. Wyzwalacze BD (ang. triggers) Wyzwalacz bazy danych jest procedurą składowaną w bazie powiązaną z jedną konkretną tablicą. Z pojedynczą tablicą może być związane wiele wyzwalaczy, natomiast pojedynczy wyzwalacz może być związany tylko z jedną tablicą. Wyzwalacze w zależności od czasu, kiedy są uruchamiane dzielą się na nastepujące grupy: before uruchamiane przed poleceniem SQL, after uruchamiane po poleceniu SQL, instead of (operujące na perspektywach) Mogą być wykonywane w wyniku poleceń: insert, update, delete. Wyzwalacz definiowany jest za pomocą polecenia: create [or replace] trigger nazwa_w np.: create or replace trigger test after delete on prac /*deklaracje zmiennych stałych, kursorów, wyjątków lokalnych wyzwalacza*/ /*ciało wyzwalacza*/ dbms_output.put_line (tekst np. 'Wiersz opisujący pracownika został usunięty'); Ciało wyzwalacza może zawierać polecenia PL/SQL i SQL oraz wywołania podprogramów, z następującymi ograniczeniami: nie wolno stosować poleceń DDL, nie wolno stosować poleceń sterowania transakcjami SQL, takimi jak commit, rollback, savepoint ani też wywoływać podprogramów zawierających te polecenia. Dla wyzwalaczy uruchamianych przez polecenia DML (insert, update, delete) można określić listę kolumn, których uaktualnienie uruchomi wyzwalacz. Np. dla tabeli prac: create or replace trigger test after insert or delete or update of etat, placa_pod on prac. Można określić, czy wyzwalacz ma być uruchamiany dla każdego wiersza tabeli, czy też niezależnie od ilości wierszy tylko jeden raz. Do tego celu służy klauzula, która jeśli występuje w definicji wyzwalacza, to będzie on uruchamiany dla każdego wiersza spełniającego warunek polecenia. W definicji wyzwalacza może być umieszczona opcjonalna klauzula when, określająca dodatkowe warunki jego uruchomienia. Wyrażenie wartościujące klauzuli musi być poleceniem SQL (bez podzapytań) i może ono zawierać dwa szczególne kwalifikatory new i old. Odwołania do tych kwalifikatorów tylko w klauzuli when nie poprzedza się dwukropkiem. Np. w tabeli prac, jeśli placa_dod jest mniejsza od 100 pracownik dostaje podwyżkę. create or replace trigger podwyżka before update on prac when (old.placa_dod<100). W klauzuli when można stosować klasyczne operatory matematyczne (=,<=,>=,!=), logiczne (and, or, not) oraz operatory SQL(is null, like, between... and, in)
np.: when(old.placa_dod between 100 and 300) Dla wyzwalacza uruchamianego poleceniem insert, kwalifikator new przyjmuje wartość null, natomiast uruchamianego poleceniem delete wartość null przyjmuje kwalifikator old. Wyzwalacz uruchamiany w update ma dostęp do nowych i starych wartości niezależnie od sposobu uruchomienia. Jako przykład użycia kwalifikatorów rozważmy wyzwalacz uruchamiany przed użyciem każdego wiersza z tabeli zesp. Pozwoli on na usunięcie jedynie tych zespołów, w których nikt nie pracuje. create or replace trigger czy_zesp_ma_prac before update on zesp v_prac number(2):=0;.select count(*) into v_prac from prac where id_zesp=:old.id_zesp; if v_prac>0 then raise_application_error(-20000,'w tym zespole są zatrudnieni pracownicy'); Uwaga! Wszystkie odwołania do kwalifikatorów new i old oprócz klauzuli when muszą być poprzedzone dwukropkiem. Ciało wyzwalacza, które jest uruchamiane przez więcej niż jedno polecenie DML może zawierać tzw. predykaty warunkowe inserting, deleting i updating, które umożliwiają wykonanie odpowiedniego fragmentu podprogramu, np. dla wyzwalacza zdefiniowanego poniżej: create or replace trigger test before insert or update or delete on prac if inserting then if updating then if deleting then polecenia predykatu updating zostaną wykonane tylko w przypadku uaktualnienie atrybutu placa_pod: update prac set placa_pod=placa_pod*1.2 where id_zesp=10; Przykład 1: automatyczna zmiana daty zatrudnienia przy zmianie zespołu CREATE TRIGGER zmiana_zespolu BEFORE UPDATE OF id_zesp ON prac FOR EACH ROW BEGIN :NEW.zatrudniony := SYSDATE; END; Do zablokowania (odblokowania) wyzwalaczy służy polecenie: alter trigger nazwa_wyzwalacza disable [enable]; Wyzwalacze związane z daną tabelą można zablokować (odblokować) poleceniem
alter table nazwa_tabeli disable [enable] all triggers; Opis wyzwalaczy zdefiniowanych przez użytkownika można odczytać przy pomocy zapytania do perspektywy systemowej USER_TRIGGERS. Wyzwalacze usuwamy poleceniem: drop trigger nazwa_wyzwalacza Uwaga! W zależności od wersji serwera bazy danych Oracle z daną tabelą może być związana różna ilość wyzwalaczy tego samego typu. Istnieje pewne ograniczenie stosowania wyzwalaczy zdefiniowanych z wykorzystaniem klauzuli. W takim wyzwalaczu nie można odwoływać się do tej samej tabeli, w której wyzwalacz został zdefiniowany. Przykład 2. Zdefiniować wyzwalacz nadający nowemu pracownikowi kolejny numer, który jest pobierany z licznika seq_prac. SQL>create or replace trigger generuj_numer before insert on prac if :new.numer is null then select seq_prac.nextval into :new.numer from dual; / Przykład 3. Zdefiniować tabelę historia_pracownik, przechowującą dane historyczne dotyczące pracowników, której schemat stanowi rozszerzenie schematu tabeli prac o trzy następujące atrybuty: użytkownik, data_operacji, rodzaj_operacji. Pierwszy z nich przechowuje nazwę użytkownika, który dokonał zmian w zawartości tabeli prac, drugi - datę dokonania tych zmian, a trzeci rodzaj operacji tj. 'UPDATE' lub 'DELETE'. Następnie zdefiniować wyzwalacz, który na skutek uaktualnienia wartości kolumn etat, szef, placa_pod, placa_dod, id_zesp lub usunięcia wierszy z tabeli prac wpisze dane z przed modyfikacji lub usunięcia do tabeli historia_pracownik. Wyzwalacz powinien również wpisać do tej tabeli nazwę użytkownika, wykonującego operację, datę wykonania i rodzaj operacji. create table historia_pracownik( numer number(4), nazwisko varchar2(12), etat varchar2(10), szef numer(4), zatrudniony date, placa_pod number(6,2), placa_dod number(6,2), id_zesp number(2), uzytkownik varchar2(12), data_operacji date, rodzaj_operacji varchar2(6)); create or replace trigger historia after update of etat, szef, placa_pod, placa_dod, id_zesp or delete on prac if updating then insert into historia_pracownik values( :old.numer, :old.nazwisko, :old.etat, :old.szef, :old.zatrudniony, :old.placa_pod, :old.placa_dod, :old.id_zesp, user, sysdate,' UPDATE');
elsif deleting then insert into historia_pracownik values( :old.numer, :old.nazwisko, :old.etat, :old.szef, :old.zatrudniony, :old.placa_pod, :old.placa_dod, :old.id_zesp, user,sysdate, 'DELETE'); end historia; Przykład 4. Za pomocą wyzwalacza zdefiniować ograniczenie integralnościowe zapewniające, że numer zespołu dla wprowadzanego lub uaktualnianego wiersza dotyczącego pracownika jest numerem jednego z już istniejących zespołów. create or replace trigger czy_zesp_istnieje before insert or update of id_zesp on prac jest:=0; select count(*) into jest from zesp where id_zesp:=new.id_zesp; if jest=0 then raise_application_error(-20000,'zespol o podanym numerze nie istnieje'); Przykład 5. Poniższy wyzwalacz sprawdza, czy na skutek uaktualnienia wierszy tabeli prac, pensja pracownika pozostaje mniejsza od pensji jego przełożonego. W przypadku, gdy tak nie jest odwołuje transakcję. Czy wyzwalacz zawsze funkcjonuje poprawnie? Po wykonaniu polecenia update prac set placa_pod=4000 where id_prac=130; na ekranie pojawi się błąd bo odwołanie się do tej tabeli za pomocą DDL mogłoby prowadzić do odczytania wartości niespójnych. create or replace trigger pensja after update of placa_pod on prac for ich row pensja_szefa number(4); select placa_pod into pensja_szefa from prac where id_prac=:old.id_szefa; if :new.placa_pod>pensja_szefa then raise_application_error( -20020,'Płaca pracownika > płacy szefa niedopuszczalne!'); 2. Wyzwalacze instead of Wyzwalacze instead of pozwalają użytkownikowi na modyfikowanie perspektyw, których zawartości nie można zmieniać używając poleceń DML (np. w przypadku perspektyw korzystających ze złączeń). Cechy odróżniające wyzwalacze instead of od wyzwalaczy before i after to: - przy uruchamianiu wyzwalacza instead of nie jest wykonywana instrukcja aktywująca wyzwalacz, - w przypadku wyzwalacza instead of ograniczenia integralnościowe typu check nie są sprawdzane, - nie można definiować wyzwalaczy instead of na tabelach,
- wszystkie wyzwalacze instead of są typu wierszowego. 3. Wyzwalacze systemowe Wyzwalacze systemowe mogą być odpalane jako reakcja na: - zdarzenie wywołane stanem systemu (uruchomienie lub zamknięcie instancji, błąd serwera); - zdarzenie wywołane przez użytkownika (zalogowanie lub wylogowanie się, wydanie polecenia DDL, albo DML). Wyzwalacze wywoływane zdarzeniami systemowymi mogą być definiowane na poziomie bazy danych (dla wszystkich użytkowników) lub na poziomie schematu (dla jednego użytkownika). Poniżej przedstawiono listę niektórych zdarzeń systemowych i opis sytuacji, w jakich aktywowany jest wyzwalacz reagujący na określone zdarzenie: STARTUP SHUTDOWN SERVERERROR AFTER LOGON BEFORE LOGOFF BEFORE CREATE AFTER CREATE BEFORE ALTER AFTER ALTER BEFORE DROP AFTER DROP BEFORE AUDIT AFTER AUDIT BEFORE NOAUDIT AFTER NOAUDIT BEFORE DDL AFTER DDL BEFORE GRANT AFTER GRANT BEFORE RENAME AFTER RENAME BEFORE REVOKE AFTER REVOKE po otwarciu bazy danych tuż przed zatrzymaniem instancji po wystąpieniu błędu po zalogowaniu się użytkownika tuż przed wylogowaniem użytkownika przed utworzeniem obiektu bazy danych po utworzeniem obiektu bazy danych przed zmianą definicji obiektu bazy danych po zmianie definicji obiektu bazy danych przed usunięciem obiektu bazy danych po usunięciem obiektu bazy danych przed wykonaniem polecenia AUDIT po wykonaniu polecenia AUDIT przed wykonaniem polecenia NOAUDIT po wykonaniu polecenia NOAUDIT przed wykonaniem większości instrukcji DDL po wykonaniu większości instrukcji DDL przed wykonaniem polecenia GRANT po wykonaniu polecenia GRANT przed wykonaniem polecenia RENAME po wykonaniu polecenia RENAME przed wykonaniem polecenia REVOKE po wykonaniu polecenia REVOKE Np.: create or replace trigger rejestr_log_wyz after logon on schema insert into rejestr_log values('zalogowano sie' sysdate); Trigger created. SQL> connect s12354/trigger Connected SQL> select * from rejestr_log; Każde zdarzenie systemowe posiada atrybuty, które można odczytać po uruchomieniu wyzwalacza. Poniżej przedstawiono listę niektórych atrybutów. ora_client_ip_address adres IP komputera klienta (jeśli jest używany
protokół TCP/IP) ora_database_name nazwa bazy danych ora_dict_obj_name nazwa obiektu bazy danych, użyta w instrukcji DLL ora_dict_obj_ovner nazwa właściciela obiektu bazy danych, którego nazwa została użyta w instrukcji DLL ora_dict_obj_type rodzaj obiektu użytego w instrukcji DLL ora_is_alter_column (kolumna IN VARCHAR2) TRUE, jeśli definicja podanej kolumny została zmieniona ora_is_drop_column (kolumna IN VARCHAR2) TRUE, jeśli podana kolumna została usunięta ora_is_servererror (numer_błędu NUMBER) TRUE, jeśli wystąpił błąd o podanym numerze ora_login_user nazwa użytkownika ora_server_error(n NUMBER) numer błędu n-ty na stosie błędów ora_sysevent nazwa zdarzenia systemowego, którego wystąpienie spowodowało odpalenie wyzwalacza Przykład 6: CREATE OR REPLACE TRIGGER obj_wyz BEFORE CREATE ON DATABASE DECLARE uzytk rejestr_log.uzytkownik%type; data rejestr_log.data%type; obiekt rejestr_log.obiekt%type; nazwa rejestr_log.obiekt%type; BEGIN uzytk:= dictionary_obj_owner; data:= SYSDATE; obiekt:= dictionary_obj_type; nazwa:= dictionary_obj_name; INSERT INTO rejestr_log VALUES(uzytk, data, obiekt, nazwa); END; CREATE TABLE tabela (kolumna NUMBER); SELECT * FROM rejestr_log; 4. Wyzwalacze z transakcją autonomiczną Wyzwalacze z transakcją autonomiczną mogą być użyteczne np. do rejestrowania transakcji, niezależnie czy zostały one zatwierdzone czy wycofane. Mogą też wykonywać (w odróżnieniu od zwykłych wyzwalaczy) polecenia DLL np.: CREATE OR REPLACE TRIGGER prac_wyzw BEFORE INSERT ON prac FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN EXECUTE IMMEDIATE 'CREATE USER' :new.nazwisko 'IDENTIFIED BY' :NWV.NAZWISKO; END; Zadania 1. Utworzyć 5 wyzwalaczy dla tabel lub widoków bazy o pracownikach.