Procedury składowane Kolejnym typem programu języka PL/SQL są procedury składowane. Procedury mogą posiadać parametry typu IN, OUT lub IN OUT. Umożliwiają wykonanie operacji na danych w bazie, mogą też służyć do wybierania danych. CREATE PROCEDURE nazwa_procedury(lista parametrów) IS deklaracje zmiennych blok poleceń Procedury z poziomu SQL wywołujemy poleceniem EXECUTE. CREATE OR REPLACE PROCEDURE wypiszkraj(nr IN INT) is CURSOR kraje2(id INT) IS SELECT * FROM countries WHERE region_id =id; FOR kraj IN kraje2(nr) loop Dbms_Output.put_line(kraj.country_name); END LOOP; CREATE OR REPLACE PROCEDURE wypiszkraj(nr IN INT) is CURSOR kraje2(id INT) IS SELECT * FROM countries WHERE region_id =id; FOR kraj IN kraje2(nr) loop Dbms_Output.put_line(kraj.country_name); END LOOP; Wywołanie procedury z poziomu SQL: EXECUTE wypiszkraj(2); Z innego podprogramu: DECLARE nr INT; nr:=1; wypiszkraj(nr); Funkcje vs. procedury Funkcja musi zwracać wartość (należy użyć RETURN); zazwyczaj ma parametry tylko typu IN; można wywoływać z poziomu zapytań SQL, np.select srednia(1,3) FROM dual; można wywoływać w kodzie innych podprogramów, ale wtedy zawsze musimy ją przypisać do zmiennej lub parametru, np. DECLARE i number; i:=srednia(1,4); Procedura może zwracać wartości; może mieć parametry typu IN, OUT, IN OUT; wywołanie w SQL przez EXECUTE; EXECUTE wypiszkraj(3); można wywoływać w kodzie innych podprogramów, np. DECLARE nr INT; nr:=1; wypiszkraj(nr);
Użycie parametrów w procedurach Procedury mogą (i zazwyczaj mają) parametry. Wyróżniamy trzy typy parametrów: IN - parametr tylko do odczytu (read-only), służy do przekazania danych do funkcji lub procedury; w trakcie działania procedury nie można zmieniać wartości tego parametru; o ile nie podamy wartości domyślnej dla danego parametru, musimy podać jego wartość wywołując procedurę; OUT - parametr wyjściowy (write-only), umożliwia zwrócenie danych przez program; ma wartość NULL do momentu zainicjalizowania; nie ma możliwości przypisania DEFAULT; wywołując procedurę, nie możemy przypisać stałej tego parametru; IN OUT - parametr wejściowo/wyjściowy (read-write); podczas wywoływania programu służy do przekazania do niego danych, umożliwia zwrócenie danych; używamy, gdy dane wejściowe mają zostać zmienione podczas działania programu; nie ma możliwości przypisania DEFAULT; wywołując procedurę, nie możemy przypisać stałej tego parametru. Podczas wywoływania procedury (funkcji), która ma kilka parametrów wejściowych, dla każdego z tych parametrów, który nie ma określonej wartości domyślnej, należy podać wartość. Jeżeli chcemy pominąć niektóre parametry, to można wówczas podczas wywoływania procedury (funkcji) określić, z którymi parametrami dana procedura została wywołana. Mamy do dyspozycji trzy notacje: pozycyjną, nazwaną i mieszaną. Podczas wywoływania procedury (funkcji), która ma kilka parametrów wejściowych, dla każdego z tych parametrów, który nie ma określonej wartości domyślnej, należy podać wartość. Jeżeli chcemy pominąć niektóre parametry, to można wówczas podczas wywoływania procedury (funkcji) określić, z którymi parametrami dana procedura została wywołana. Mamy do dyspozycji trzy notacje: pozycyjną, nazwaną i mieszaną. CREATE OR REPLACE FUNCTION suma (a INT :=0, b INT :=0, c INT :0) RETURN INT AS RETURN a+b/2+c/4; Podczas wywoływania procedury (funkcji), która ma kilka parametrów wejściowych, dla każdego z tych parametrów, który nie ma określonej wartości domyślnej, należy podać wartość. Jeżeli chcemy pominąć niektóre parametry, to można wówczas podczas wywoływania procedury (funkcji) określić, z którymi parametrami dana procedura została wywołana. Mamy do dyspozycji trzy notacje: pozycyjną, nazwaną i mieszaną. CREATE OR REPLACE FUNCTION suma (a INT :=0, b INT :=0, c INT :0) RETURN INT AS RETURN a+b/2+c/4; Wywołanie funkcji w SELECT: select suma(1,2,8) from dual; //a=1,b=2,c=8 select suma(1,4) from dual; //a=1,b=4 select suma(c=>8,a=>2,b=>6) from dual; select suma(1,c=>4) from dual; // a=1, c=4
Wywoływanie procedur i funkcji w odrębnej transakcji Domyślnie, funkcje i procedury działają w obrębie tej samej transakcji, co polecenie lub program je wywołujący. Można także ustawić funkcje i procedury tak, aby były wykonywane w obrębie autonomicznej, lokalnej transakcji. Taka transakcja może być zatwierdzona niezależnie od transakcji programu wywołującego. W ten sposób wszystkie zmiany wprowadzone przez funkcję/procedurę zostają zatwierdzone, bez względu na to, co wykona się w programie wywołującym. Uwaga. działanie to jest pożądane, jeżeli chcemy aby pewne zmiany zostały zatwierdzone, niezależnie od tego, czy coś innego się powiedzie. Może jednak doprowadzić do tego, że zatwierdzimy zmiany, które nie powinny zostać w danej sytuacji zatwierdzone. Aby określić, że procedura/funkcja ma być wykonywana w autonomicznej transakcji, używamy dyrektywy PRAGMA AUTONOMOUS_TRANSACTION. Do zarządzania autonomiczną transakcją wykorzystujemy COMMIT, ROLLBACK i SAVEPOINT. CREATE OR REPLACE FUNCTION dodaj_kraj (vcountry_id CHAR, vcountry_name VARCHAR2, vregion_id NUMBER ) RETURN BOOLEAN IS -ustawiamy funkcję aby wykonywała się w autonomicznej transakcji PRAGMA autonomous_transaction; -ustawiamy domyślny wynik wynik BOOLEAN :=FALSE; INSERT INTO countries VALUES(vcountry_id, vcountry_name, vregion_id); -zatwierdzamy lokalną transakcję COMMIT; wynik:=true; RETURN wynik; Sekwencje Wywołanie funkcji dodaj_kraj w bloku anonimowym: IF dodaj_kraj( PL, Polska,1) THEN Dbms_Output.put_line( wiersz wstawiony ); ROLLBACK;-bez wpływu na wstawiony wiersz! ELSE Dbms_Output.put_line( wiersz nie wstawiony ); END IF; Sekwencje w bazie Oracle to mechanizmy umożliwiające generowanie kolejnych wartości liczbowych. Instrukcja tworząca sekwencję: CREATE SEQUENCE nazwa INCREMENT BY liczba START WITH liczba Znaczenie opcji INCREMENT BY liczba skok sekwencji (domyślnie 1), START WITH liczba wartość początkowa (domyślnie 1). Metody sekwencji: CURRVAL pobranie bieżącej wartości, NEXTVAL pobranie następnej wartości.
Sekwencje Sekwencje Definiujemy sekwencję dla klucza głównego emp_no tabeli employee: CREATE SEQUENCE emp_no_seq INCREMENT BY 1 START WITH 200 Wykorzystanie sekwencji: INSERT INTO employee (emp_no, first_name, last_name, salary, dept_no, hire_date, job_code, job_grade, job_country) VALUES(emp_no_seq.NEXTVAL, Anna, Kowalska,5000, 000,sysdate, Admin,4, USA ); Każde wywołanie metody NEXTVAL powoduje zwiększenie wartości sekwencji o zadany skok. Jeżeli wartość ta nie zostanie wykorzystana, np. z powodu błędu w instrukcji INSERT, wycofania transakcji, zostaje utracona. Przy następnym wywołaniu NEXTVAL zwraca kolejną wartość. Jedną sekwencję można wykorzystywać do generowania wartości kluczy głównych w kilku tabelach. Metoda CURRVAL nie zmienia wartości sekwencji, a jedynie zwraca bieżącą. Uwaga. Metodę CURRVAL można stosować dopiero po pobraniu pierwszej wartości z sekwencji za pomocą NEXTVAL. Wyjatki Typy wyjatków Wyjątki błędy pojawiające się podczas uruchomienia bloku. W momencie wystąpienia wyjątku blok kończy działanie. Obsługując wyjątek można wykonać pewne działania przed końcem wykonania bloku. Typy wyjatków: predefiniowane (np. NO_DATA_FOUND, ZERO_DIVIDE) oraz niepredefiniowane błędy serwera Oracle; Z każdym takim wyjątkiem związany jest kod błędu (SQLCODE) oraz komunikat (SQLERRM), który opisuje błąd (zawiera też kod błędu). wywoływane przez użytkownika za pomocą RAISE nazwa, gdzie nazwa została zdefiniowana jako wyjątek z dodaną obsługą. Etapy obsługi wyjątków: Deklaracja (jawna lub niejawna). Wywołanie wyjątku (jawne lub niejawne). Obsługa wyjątku (jawna lub niejawna) Predefiniowany błąd serwera Oracle. Jeden z wyjątków (około 20) które pojawiają się najczęściej w PL/SQL. Wyjątków predefiniowanych nie trzeba ani deklarować ani zgłaszać. Oracle sam definiuje obsługę. Niepredefiniowany błąd serwera Oracle. Inny standardowy błąd serwera. Obsługa powinna być zdefiniowana. Błędy zdefiniowane przez użytkownika. Konieczna deklaracja wyjątku oraz wywołanie za pomocą RAISE.
Obsługa wyjatków sekcja EXCEPTION bloku DECLARE EXCEPTION WHEN wyjatek1 [OR wyjatek2 ] THEN instrukcje; WHEN wyjatek3 [OR wyjatek4 ] THEN instrukcje; WHEN OTHERS THEN instrukcje; Predefiniowane wyjatki Oracle Wyjątek Numer błędu Opis CASE_NOT_FOUND ORA-06592 Brak spełnienia jednego z warunków CASE CURSOR_ALREADY ORA-06511 Kursor został już otwarty _OPENED (przy próbie otwarcia) DUP_VAL ORA-00001 Powtarzająca się wartość _ON_INDEX klucza głównego INVALID_NUMBER ORA-01722 Zły typ danych przy konwersji NO_DATA_FOUND ORA-01403 Brak wyników z SELECT ROWTYPE ORA-06504 Różne typy dla przypisywanych _MISMATCH wartości STORAGE_ERROR ORA-06500 Nie ma pamięci do operacji TOO_MANY_ROWS ORA-01422 Zbyt wiele wierszy zwróconych z zapytania VALUE_ERROR ORA-06502 Błąd związany z liczbami (np. konwersja) ZERO_DIVIDE ORA-01476 Próba dzielenia przez 0 Wyjatki użytkownika Związane tylko z danym programem PL/SQL. Nie są skojarzone z żadnym numerem błędu ani komunikatem. Proces tworzenia i obsługi wyjątków: Deklaracja zmiennej typu EXCEPTION (w sekcji DECLARE); nazwa EXCEPTION Wywołanie wyjątku w wyniku instrukcji RAISE (w sekcji instrukcji wykonywalnych); RAISE nazwa Zdefiniowanie obsługi błędu dla zadeklarowanej zmiennej (w sekcji EXCEPTION). WHEN nazwa THEN W Oracle mamy możliwość tworzenia nowych błędów z własnym kodem i opisem. Używamy w tym celu procedury RAISE_APPLICATION_ERROR( err_no number, err_msg varchar2, keep_errors boolean) err_no numer z przedziału [-20000, -20999] err_msg napis o długości <512 keep_errors, jeżeli true, to nowy błąd zostanie dopisany do listy już zdefiniowanych błędów, jeżeli false (wartość domyślna), to nowy błąd zastąpi listę już zgłoszonych błędów. ProceduraRAISE_APPLICATION_ERROR powoduje zatrzymanie działania programu. Pozwala stworzyć zestaw komunikatów dopasowany do danej aplikacji.
Niepredefiniowane błędy Oracle Wyjatki Oracle Przykłady takich błędów: naruszenie więzów klucza głównego lub obcego; naruszenie ograniczeń kolumny (np. CHECK, NOT NULL). Mechanizm obsługi: DECLARE - deklaracja wyjątku użytkownika wyjatek EXCEPTION; - kojarzenie błędu z wyjątkiem użytkownika PRAGMA EXCEPTION_INIT(wyjatek, kod_bledu); EXCEPTION WHEN wyjatek THEN Z każdym wyjątkiem Oracle związany jest typ oraz numer błędu i odpowiedni komunikat. Niepredefiniowane błędy Oracle można obsłużyć związując taki błąd z wyjątkiem zdefiniowanym przez użytkownika, lub używając klauzuliwhen OTHERS THEN w sekcji EXCEPTION bloku, wykorzystując funkcje SQLCODE (zwraca kod błędu) i SQLERRM (zwraca komunikat błędu). Typy błędów: PLS podczas kompilacji; ORA podczas wykonania. Wyjatki Oracle Wyjatki Oracle Wyjątki, które nie zostały zdefiniowane, warto logować w specjalnych tabelach. Przykład takiego mechanizmu: EXCEPTION WHEN OTHERS THEN blad_numer := SQLCODE; info_blad := SQLERRM; INSERT INTO bledy(uzytkownik, data, blad, tresc) VALUES (USER, SYSDATE, blad_numer,info_blad); Listę wyjątków predefiniowanych Oracle można znaleźć np. na stronie: http://docs.oracle.com/cd/b19306_01/appdev.102/b14261/errors.htm Listę kodów błędów Oracle można znaleźć np. na stronie: http://docs.oracle.com/cd/b14117_01/server.101/b10744/toc.htm