Plan wykładu Spis treści 1 Dynamiczny SQL 1 2 Wyzwalacze 2 3 Podsumowanie 9 4 Źródła 9 1 Dynamiczny SQL Dynamiczny SQL Dynamiczny SQL - technika programowania umożliwiająca generowanie instrukcji SQL dynamicznie - w trakcie wykonywania programu. Instrukcja taka jest zapisana w aplikacji w postaci łańcucha, którego zawartość może ulegać zmianie. Używany kiedy pełna treść instrukcji SQL jest nieznana przed uruchomieniem programu. Czyni programy napisane w PL/SQL bardziej ogólnymi i elastycznymi. Pozwala na zapisywanie i wykonywanie instrukcji DDL, DCL i TCL z poziomu kodu PL/SQL. Jest wykonywany w natywnym dynamicznym SQLu (ang. Native Dynamic SQL - NDS) albo z pakietu DBMS SQL. Użycie natywnego dynamicznego SQLa - NDS Wykonanie instrukcji dynamicznego SQL a wewnątrz bloku PL/SQL umożliwia polecenie EXECUTE IMMEDIATE. EXECUTE IMMEDIATE dynamic_string [INTO {zmienna1 [,zmienna2]... rekord} ] [USING [IN OUT IN OUT] agrument_zwiazany1 [, [IN OUT IN OUT] agrument_zwiazany2]... ]; Dla zapytania wielowierszowego używamy OPEN-FOR, FETCH i CLOSE. Dynamiczny SQL - przykłady CREATE OR REPLACE PROCEDURE exe_fun (p_fun CHAR) AS v_fun VARCHAR2(7); IF Upper(p_fun) LIKE 'U' THEN v_fun := 'Upper'; ELSIF Upper(p_fun) LIKE 'I' THEN v_fun := 'Initcap'; ELSIF Upper(p_fun) LIKE 'L' THEN 1
v_fun := 'Lower'; EXECUTE IMMEDIATE 'UPDATE dzieci SET nazwisko =' v_fun '(nazwisko)'; END exe_fun; Dynamiczny SQL - przykłady CREATE OR REPLACE PROCEDURE usun_tabele (p_nazwa VARCHAR2) AS EXECUTE IMMEDIATE 'DROP TABLE ' p_nazwa; END usun_tabele; / EXECUTE usun_tabele('test'); Dynamiczny SQL - parametryzacja CREATE OR REPLACE PROCEDURE dodaj_dzial (p_nazwa VARCHAR2, p_siedziba VARCHAR2) AS v_id dzialy.id_dzialy%type; EXECUTE IMMEDIATE 'SELECT MAX(id_dzialu) FROM dzialy' INTO v_id; EXECUTE IMMEDIATE 'INSERT INTO dzialy VALUES (:1, :2, :3)' USING v_id+10, p_nazwa, p_siedziba; COMMIT; END dodaj_dzial; 2 Wyzwalacze Wyzwalacze Wyzwalacz - procedura wyzwalana, składowana fizycznie w bazie, uruchamiana automatycznie po nastąpieniu określonego w definicji zdarzenia. Wyzwalacz może być zdefiniowany na tabeli, perspektywie, schemacie albo bazie danych. Składowe wyzwalacza (ECA): określenie zdarzenia (Event) określenie warunku (Condition) określenie akcji (Action) 2
Zastosowanie wyzwalaczy Automatyczne generowanie wartości. Zapewnienie integralności referencyjnej pomiędzy węzłami w rozproszonej bazie danych. Wypełnienie kolumn wartościami domyślnymi. Zapobieganie błędnym transakcjom. Wprowadzenie skomplikowanych funkcji autoryzujących. Zapewnienie niestandardowych więzów integralności. Realizacja złożonej logiki biznesowej. Monitorowanie działań użytkowników. Realizacja synchronicznej replikacji tabel. Prowadzenie statystyk. Zapewnienie dodaktowych reguł bezpieczeństwa. Modyfikacja złożonych perspektyw. itp. Podział wyzwalaczy Typy wyzwalaczy ze względu na rodzaj zdarzenia, reagujące na: instrukcje DML (INSERT, UPDATE, DELETE), instrukcje DDL (CREATE, ALTER, DROP), zdarzenia systemowe (SERVERERROR, LOGON, LOGOFF,...), zdarzenia użytkownika, Typy wyzwalaczy ze względu na poziom wywołania: wierszowe (ang. row-level), poleceniowe (ang. statement-level), Typy wyzwalaczy ze względu na czas wywołania: przed wykonaniem instrukcji (BEFORE), po wykonaniu instrukcji (AFTER), zamiast wykonania instrukcji (INSTEAD OF). 3
Tworzenie wyzwalacza CREATE [OR REPLACE] TRIGGER [schemat.] nazwa { { BEFORE AFTER INSTEAD OF } zdarzenie_dml [OR zdarzenie_dml]... { BEFORE AFTER } { zdarzenie_ddl [OR zdarzenie_ddl]... zdarzenie_systemowe [OR zdarzenie_systemowe]... } ON { [schemat.] SCHEMA DATABASE } } [ FOLLOWS [schemat.] wyzwalacz [, [schemat.] wyzwalacz ]... ] [ ENABLE DISABLE ] [ WHEN ( warunek ) ] { blok_plsql blok_zlozonego_wyzwalacza CALL skladowana_procedura } Opis zdarzenia DML { DELETE INSERT UPDATE [OF kolumna1 [, kolumna2]...] } [ OR { DELETE INSERT UPDATE [OF kolumna1 [, kolumna2]...] } ]... ON { [schemat.] tabela [schemat.] perspektywa } [FOR EACH ROW] Np.: CREATE OR REPLACE TRIGGER zmiana_placy AFTER UPDATE OF placa ON pracownicy INSERT INTO dziennik VALUES ('pracownicy',current_date, NULL, 'Zmieniono place'); Operacje na wyzwalaczach Wyłączanie wyzwalacza: ALTER TRIGGER nazwa DISABLE; Włączenie wyzwalacza: ALTER TRIGGER nazwa ENABLE; Usunięcie wyzwalacza: DROP TRIGGER nazwa; 4
Ograniczenia wyzwalaczy Ograniczenia stosowania wyzwalaczy: wielkość wyzwalacza nie może przekraczać 32K, nie mogą wykonywać instrukcji DDL, nie mogą wykonywać instrukcji sterujących transakcjami (poza wywołaniem wewnątrz transakcji autonomicznej), wyzwalacze wierszowe nie mogą modyfikować ani wykonywać zapytania do obiektu, dla którego zostały wywołane, dotyczy to również tabel, które mogły być zmodyfikowane w wyniku operacji ON DELETE SET NULL lub ON DELETE CASCADE, dwa powyższe chronią wyzwalacze przed odczytem niespójnych danych. Wyzwalacze polecenia Wyzwalacze polecenia: Np.: domyślny typ wyzwalacza, wykonane jednokrotnie dla wywołującego je zdarzenia, wykonane jednokrotnie nawet jeśli żaden wiersz nie został zmieniony, nie posiadają dostępu do poszczególnych elementów, które mogły ulec zmianie. CREATE OR REPLACE TRIGGER duze_nazwiska AFTER INSERT ON pracownicy UPDATE pracownicy SET nazwisko = Upper(nazwisko); Wyzwalacze wierszowe Wyzwalacze wierszowe: wymagają użycia klauzuli FOR EACH ROW, uruchamianie jednorazowo dla każdego zmienionego wiersza, nie wywoływane, jeśli zdarzenie uruchamiające wyzwalacz nie zmieniło ani jednego wiersza, posiadają dostęp do poszczególnych elementów, które mogły ulec zmianie poprzez przedrostki :OLD i :NEW. INSERT UPDATE DELETE :NEW + + - :OLD - + + 5
Wyzwalacze wierszowe - przykład CREATE OR REPLACE TRIGGER duze_nazwiska BEFORE INSERT ON pracownicy FOR EACH ROW :New.nazwisko:=Upper(:New.nazwisko); Warunek uruchomienia wyzwalacza CREATE OR REPLACE TRIGGER podwyzki BEFORE UPDATE OF placa ON pracownicy FOR EACH ROW WHEN (NEW.stanowisko NOT LIKE 'PREZES') IF :NEW.placa > :OLD.placa * 1.1 THEN :NEW.placa := :OLD.placa * 1.1; Wykrywanie zdarzenia DML aktywującego wyzwalacz Dla więcej niż jednego zdarzenia DML mogącego uruchomić wyzwalacz mamy dostępne predykaty warunkowe pozwalające sprawdzić, które zdarzenie wyzwalacz uruchomiło. Predykaty: INSERTING - zwraca prawdę, kiedy dokonano wstawienia danych, UPDATING - zwraca prawdę, kiedy dokonano zmiany danych, DELETING - zwraca prawdę, kiedy dokonano skasowania danych. CREATE OR REPLACE TRIGGER zmiana_osob AFTER INSERT OR DELETE OR UPDATE ON osoby FOR EACH ROW IF INSERTING THEN INSERT INTO audyt VALUES(Current_date, 'Wstawiono dane w tabeli osoby'); IF DELETING THEN INSERT INTO audyt VALUES(Current_date, 'Skasowano dane z tabeli osoby'); IF UPDATING THEN INSERT INTO audyt VALUES(Current_date, 'Modyfikowano dane w tabeli osoby'); 6
Wyzwalacze INSTEAD OF Wyzwalacze INSTEAD OF: stosowane wyłącznie dla perspektyw, wykonywane zamiast instrukcji aktywującej wyzwalacz ograniczenia typu CHECK nie są sprawdzane, zawsze typu wierszowego (FOR EACH ROW). CREATE VIEW prac_dzial AS SELECT * FROM pracownicy NATURAL JOIN dzialy; CREATE OR REPLACE TRIGGER prac_dzial_t INSTEAD OF INSERT OR UPDATE ON prac_dzial --... sprawdzamy czy pracownik już nie istnieje INSERT INTO pracownicy VALUES (:NEW.nr_akt, :NEW.nazwisko, :NEW.stanowisko, :NEW.kierownik, :NEW.data_zatr, :NEW.data_zwol, :NEW.placa, :NEW.dod_funkcyjny, :NEW.prowizja, :NEW.id_dzialu); --... sprawdzamy czy dzial już nie istnieje INSERT INTO dzialy VALUES (:NEW.id_dzialu, :NEW.nazwa, :NEW.siedziba); Wyzwalacze systemowe Wyzwalacze systemowe moga być wywołane dla danego schematu (jednego użytkownika), bądź dla całej bazy danych (dla wszystkich użytkowników). Są aktywowane: przez zdarzenia zmiany stanu systemu, zdarzenia wywołane zachowaniem użytkownika. CREATE [OR REPLACE] TRIGGER [schemat.] nazwa { BEFORE AFTER } { zdarzenie_ddl [OR zdarzenie_ddl]... zdarzenie_systemowe [OR zdarzenie_systemowe]... } ON { [schemat.] SCHEMA DATABASE } [WHEN ( warunek ) ] { blok_plsql blok_zlozonego_wyzwalacza CALL skladowana_procedura } Wyzwalacze systemowe - przykłady Wyzwalacze systemowe: BEFORE AFTER ALTER - przed/po zmianie definicji obiektu BEFORE AFTER DROP - przed/po usunięciu obiektu BEFORE AFTER CREATE - przed/po utworzeniu obiektu 7
BEFORE AFTER RENAME - przed/po zmianie nazwy obiektu BEFORE AFTER DDL - przed/po wykonaniu większości instrukcji DDL BEFORE AFTER GRANT - przed/po nadaniu uprawnień BEFORE AFTER REVOKE - przed/po odebraniu uprawnień AFTER LOGON - po zalogowaniu BEFORE LOGOFF - przed wylogowaniem Wyzwalacze systemowe wyłącznie dla bazy danych: AFTER STARTUP - po otwarciu bazy danych AFTER SERVERERROR - po wystapieniu błędu BEFORE SHUTDOWN - przed zatrzymaniem instancji bazy CREATE OR REPLACE TRIGGER blokada_drop BEFORE DROP ON SCHEMA RAISE_APPLICATION_ERROR(-20123, 'Próba usuwania obiektów przez ' User ' numer ' Uid); CREATE TRIGGER log_errors AFTER SERVERERROR ON DATABASE IF (IS_SERVERERROR (1017)) THEN INSERT INTO server_audit(current_timestamp, 'Error - 1017') Wytyczne do projektowania wyzwalaczy Używaj wyzwalaczy żeby zagwarantować, że kiedy wykona się specyficzna czynność, wykonają się również inne wymagane czynności. Nie projektuj wyzwalaczy, które powielają funkcje bazy danych. Używaj aby zapewnić integralność referencyjną kiedy tabele dziecka i rodzica znajdują się na różnych węzłach rozproszonej bazy danych. Używaj aby dostarczyć skomplikowaną logikę biznesową nieosiągalną poprzez ograniczenia i więzy nadawane tabelom. Ograniczaj wielkośc wyzwalaczy (nie mogą być większe niż 32K). 8
Nie twórz rekukrencyjnych wyzwalaczy. Używaj wyzwalaczy dla scentralizowanych, globalnych operacji uruchamianych poprzez polecenia niezależne od tego kto je wykonał (użytkownik czy baza danych). Twórz wyzwalacze dla poziomu DATABASE rozsądnie ponieważ są one uruchamiane dla każdego użytkownika za każdym razem kiedy dane zdarzenie będzie mieć miejsce. Jeśli tworzysz wyzwalacz na zdarzeniu LOGON, koniecznie dołącz obsługę wyjątków uwzględniającą wyjątek WHEN OTHERS. W przeciwnym razie jakiś niewychwycony błąd może zablokować wszystkim użytkownikom możliwość logowania się. Jeśli używasz wyzwalacza działającego na LOGON tylko do uruchomienia pakietu, np. do przygotowania środowiska pracy użytkowników, umieść sekcje obsługi wyjątków wewnątrz pakietu zamiast w wyzwalaczu. 3 Podsumowanie Podsumowanie PL/SQL umożliwia: modyfikację danych za pośrednictwem perspektyw złożonych, obsługę sytuacji wyjątkowych, obsługę zdarzeń z użyciem wyzwalaczy, wprowadzenie złożonych zależności i ograniczeń integralności. 4 Źródła Źródła W wykładzie wykorzystano materiały: http://www.techonthenet.com/oracle/ M. Lentner, Oracle 9i Kompletny podręcznik użytkownika, PJWSTK - W-wa, 2003 http://docs.oracle.com/cd/b28359_01/appdev.111/b28370/triggers.htm http://docs.oracle.com/cd/b28359_01/appdev.111/b28370/create_trigger. htm 9