Wyzwalacze Wyzwalacze są specjalnymi procedurami składowanymi, uruchamianymi automatycznie w następstwie zaistnienia określonego typu zdarzenia. Ich główne zadanie polega na wymuszaniu integralności danych i zapewnienie, aby dane przechowywane w bazie były zgodne z regułami narzuconymi przed projektanta bazy. Każdy wyzwalacz jest związany z określoną tabelą (lub widokiem) i jest uruchamiany w następstwie zajścia jednego z trzech zdarzeń: wywołanie instrukcji INSERT, UPDATE lub DELETE dla danej tabeli (widoku). Dodatkowo, można określić kiedy wyzwalacz ma zostać uruchomiony: przed zdarzeniem (wyzwalacz typu BEFORE), po zdarzeniu (AFTER) lub zamiast zdarzenia (INSTEAD OF) (ten typ wyzwalaczy stosujemy do widoków). W bazach danych Oracle mamy dwa rodzaje wyzwalaczy: wierszowe (które definiujemy za pomocą klauzuli FOR EACH ROW) oraz obiektowe.
Składnia instrukcji tworzacej wyzwalacz CREATE OR REPLACE TRIGGER nazwa BEFORE / AFTER / INSTEAD OF INSERT / UPDATE / DELETE OR dodatkowe zdarzenie ON tabela/widok FOR EACH ROW ciało wyzwalacza Jeden wyzwalacz może zostać zdefiniowany dla kilku zdarzeń, np. aby zdefiniować wyzwalacz wierszowy dla tabeli employee, wywoływany po instrukcji UPDATE lub INSERT, użyjemy składni: CREATE OR REPLACE TRIGGER nowy AFTER INSERT OR UPDATE ON employee FOR EACH ROW...
Za pomocą wyzwalaczy można zrealizować wiele istotnych, z punktu widzenia integralności i bezpieczeństwa danych, zadań, m.in. zapewnienie integralności danych; sprawdzanie reguł poprawności wstawianych (modyfikowanych) danych; logowanie zdarzeń w systemie; można stworzyć własną tabelę z logami, a następnie wyzwalacze, które będą do tej tabeli wstawiać kolejne wiersze w odpowiedzi na działania na obiektach bazy danych; modyfikowanie danych, które mają zostać wstawione do tabeli (np. odpowiednie formatowanie) przed ich umieszczeniem w tabeli
Kwalifikatory new i old w wyzwalaczach wierszowych W ciele wyzwalacza można korzystać ze wszystkich instrukcji, które są dostępne dla procedur zapamiętanych. W wyzwalaczach wierszowych mamy dodatkowo dostępne dwa kwalifikatory new oraz old, które pozwalają odwoływać się odpowiednio do nowych lub poprzednich wartości pól wstawianego lub usuwanego czy modyfikowanego wiersza. Uwaga. Dla wyzwalaczy uruchamianych w następstwie wykonania instrukcji INSERT mamy dostępne tylko wartości new, dla wyzwalaczy dla DELETE tylko wartości old, natomiast w przypadku zdarzenia UPDATE dostępne są obie wartości. Dla przykładu, jeżeli mamy zdefiniowany wyzwalacz wierszowy dla tabeli employee, dla zdarzenia UPDATE, to aby odwołać się do poprzedniej wartości zarobków w modyfikowanym wierszu, należy użyć składni :old.salary, natomiast aby odczytać nową wartość zarobków, należy użyć odwołania :new.salary.
Uwaga. W ciele wyzwalacza nie może być instrukcji, które modyfikują strukturę tabeli, na którą nałożony jest wyzwalacz; modyfikują dane w tabeli, dla której zdefiniowany jest dany wyzwalacz; wpływają na transakcję; odowłują się do podprogramów (procedur, funkcji), które zawierają takie instrukcje.
Stosowanie predykatów INSERTING, UPDATING, DELETING Czasem wygodnie jest mieć wyzwalacz, który jest wywoływany w odpowiedzi na zajście więcej niż jednego ze zdarzeń INSERT, UPDATE, DELETE. Jeżeli mamy taki wyzwalacz, to musimy mieć możliwość sprawdzić, które zdarzenie wywołało ten wyzwalacz. W tym celu można użyć predykatów INSERTING, UPDATING, DELETING. Predykatów można użyć np. w warunku instrukcji IF, aby móc wykonać różne operacje, w zależności od tego, jaka instrukcja została wykonana.
Zarzadzanie wyzwalaczami Do usuwania wyzwalaczy służy instrukcja DROP TRIGGER nazwa. Często nie chcemy usuwać wyzwalacza, a jedynie go czasowo dezaktywować (wyzwalacze wydłużają czas wykonywania modyfikacji, jeżeli planujemy przeprowadzić dużą liczbę instrukcji DML, aby przyspieszyć działanie, można przedtem wyłączyć pewne wyzwalacze). Wyzwalacz wyłączamy instrukcją ALTER TRIGGER nazwa DISABLE. Aby ponownie aktywować wyzwalacz, należy użyć instrukcji ALTER TRIGGER nazwa ENABLE. Dla jednej tabeli może być zdefiniowanych kilka wyzwalaczy tego samego typu. Są one wówczas uruchamiane sekwencyjnie.
Pakiety Pakiety są logicznymi zbiorami obiektów takich jak podprogramy, typy, zmienne, kursory, wyjątki. Pakiet składa się ze: specyfikacji (interfejsu) i ciała (implementacji). W specyfikacji mieszczą się deklaracje typów, zmiennych, stałych, kursorów, wyjątków i podprogramów. W ciele mieści się implementacja specyfikacji. Specyfikacja i ciało pakietu są oddzielnie przechowywane w słowniku danych.
Pakiety umożliwiają: 1 przechowywanie powiązanych ze sobą obiektów w jednym miejscu, 2 grupowanie logicznej funkcjonalności, 3 łatwe projektowanie aplikacji: kodowanie i kompilacja oddzielnie specyfikacji i ciała, 4 ukrywanie informacji: tylko deklaracje w specyfikacji są jawne i dostępne dla aplikacji, prywatne deklaracje w ciele pakietu są ukryte, kod jest ukryty w ciele pakietu.
Zalety pakietów: zwiększenie wydajności (przy pierwszym odwołaniu do pakietu cała jego zawartość jest ładowana do pamięci), dodatkowa funkcjonalność udostępniają zmienne globalne, umożliwiają przeciążanie procedur i funkcji, ukrycie informacji użytkownikowi jest udostępniana tylko specyfikacja pakietu (interfejs), natomiast implementacja procedur i funkcji jest niewidoczna,
Definiowanie pakietu Specyfikacja: CREATE OR REPLACE PACKAGE nazwa_pakietu IS deklaracje typów, stałych, zmiennych, kursorów i wyjątków dostępnych na zewnątrz pakietu deklaracje funkcji i procedur END; Ciało: CREATE OR REPLACE PACKAGE BODY nazwa_pakietu IS deklaracje lokalnych typów, zmiennych, stałych, wyjatków i kursorów definicje procedur i funkcji BEGIN części inicjalizacyjna pakietu END;
Każda deklaracja funkcji i procedury ze specyfikacji pakietu musi mieć odzwierciedlenie w ciele, specyfikacja procedur i funkcji w obu częściach pakietu musi być dokładnie taka sama jeśli chodzi o nazwę podprogramu, nazwy parametrów i ich typy. Zmienne i kursory mogą być inicjalizowane w części inicjalizacyjnej pakietu.
Przykład (z dokumentacji Oracle) Specyfikacja: CREATE OR REPLACE PACKAGE emp_actions IS TYPE EmpRecTyp IS RECORD (emp_id INT, salary REAL); CURSOR desc_salary RETURN EmpRecTyp; PROCEDURE hire_employee ( ename VARCHAR2, job VARCHAR2, mgr NUMBER, sal NUMBER, comm NUMBER, deptno NUMBER); PROCEDURE fire_employee (emp_id NUMBER); END;
Ciało: CREATE OR REPLACE PACKAGE BODY emp_actions IS CURSOR desc_salary RETURN EmpRecTyp IS SELECT empno, sal FROM emp ORDER BY sal DESC; PROCEDURE hire_employee ( ename VARCHAR2, job VARCHAR2, mgr NUMBER, sal NUMBER, comm NUMBER, deptno NUMBER) IS BEGIN INSERT INTO emp VALUES (empno_seq.nextval, ename, job, mgr, SYSDATE, sal, comm, deptno); END; PROCEDURE fire_employee (emp_id NUMBER) IS BEGIN DELETE FROM emp WHERE empno = emp_id; END; END;
Odwołanie do funkcji/procedury zawartej w pakiecie należy poprzedzić nazwą pakietu, o ile odwołujemy się do danej funkcji/procedury z zewnątrz pakietu, np. EXECUTE emp_actions.fire_employee(2); Kompilowanie pakietu: ALTER PACKAGE nazwa COMPILE PACKAGE PACKAGE BODY; Usuwanie pakietu: DROP PACKAGE PACKAGE BODY nazwa;
Użycie pakietów do deklarowania zmiennych globalnych Jeżeli specyfikacja pakietu nie zawiera deklaracji kursorów ani podprogramów, a jedynie typy, stałe, zmienne i wyjątki, wówczas nie ma konieczności tworzenia ciała pakietu, jak w poniższym przykładzie (z dokumentacji Oracle): CREATE PACKAGE trans_data IS TYPE TimeRec IS RECORD ( minutes SMALLINT, hours SMALLINT); TYPE TransRec IS RECORD ( category VARCHAR2, account INT, amount REAL, time_of TimeRec); minimum_balance CONSTANT REAL := 10.00; number_processed INT; insufficient_funds EXCEPTION; END; Tego typu pakiet umożliwia zdefiniowanie zmiennych globalnych, do których można się odwoływać z podprogramów oraz wyzwalaczy, w obrębie danej sesji.
Przeciażanie podprogramów z pakietów W pakiecie mogą znajdować się funkcje lub procedury o takiej samej nazwie, ale w wersjach z różnymi parametrami, Pozwala to na stosowanie tych samych operacji do różnych typów obiektów, Parametry muszą się różnić w liczbie, kolejności lub typie, Nie można utworzyć dwóch podprogramów o tej samej nazwie, jeśli ich parametry różnią się tylko nazwą lub trybem (IN, OUT czy IN OUT). Nie można utworzyć dwóch funkcji jeśli różnią się tylko typem zwracanej wartości. np. CREATE OR REPLACE PACKAGE pracownik IS FUNCTION srednia_zarobkow(id_dzialu NUMBER) RETURN NUMBER; FUNCTION srednia_zarobkow(id_dzialu NUMBER, id_managera NUMBER) RETURN NUMBER; END;