Laboratorium Baz Danych
O R A C L E
PL/SQL
1. Wstęp
PL/SQL jest proceduralnym rozszerzeniem SQL'a firmy ORACLE. Programy napisane w języku PL/SQL mogą być uruchamiane nie tylko w środowisku SQL*Plus'a, ale również w wyspecjalizowanych narzędziach takich jak SQL*DBA, SQL*Forms, SQL*Menu oraz w OCI (Oracle Programmatic Interfaces).
PL/SQL jest językiem strukturalnym. Kod zapisywany jest blokami otoczonymi zdaniami BEGIN i END. Zmienne mogą być deklarowane zdaniem. Dla zmiennych PL/SQL'a używanych do kolumn bazy danych można podać atrybut %TYPE, co oznacza żądanie dynamicznego określenia typu w czasie wykonywania. Wszelkie zmiany w typie danych automatycznie spowodują zmianę typu zmiennej PL/SQL'a. Zbędne są jakiekolwiek zmiany w kodzie.
PL/SQL pozwala stosować wszystkie instrukcje SQL'a manipulowania danymi, włączając w to instrukcje INSERT, UPDATE, DELETE i SELECT, również operacje na kursorach i przetwarzanie transakcyjne. Bloki PL/SQL'a mogą zawierać dowolną liczbę instrukcji SQL'a.
2. Podstawy
2.1. Notacja syntaktyczna
Notacja używana w przykładach:
< > element syntaktyczny
-- rozpoczęcie wiersza komentarza
/* rozpoczęcie wielowierszowego komentarza
*/ zakończenie wielowierszowego komentarza
. separator występujący między nazwą obiektu i nazwą komponentu
.. separator pomiędzy dolną i górną wartością przedziału
... zaznaczenie kontynuacji kodu
Notacja używana w opisie składni instrukcji PL/SQL:
[ ] opcjonalny element
{ 'D jeden z elementów
| separator alternatywy wyboru
... oznaczenie powtarzalności elementu
2.2. Typy danych
Każda stała i zmienna jest określonego typu. PL/SQL udostępnia stosowanie typów skalarnych i złożonych
Typy skalarne Typy złożone
----------------------------------------------------- ------------------------------
BINARY_INTEGER CHAR RECORD TABLE
DEC CHARACTER
DECIMAL LONG
DOUBLE PRECISION LONG RAW
FLOAT RAW
INT ROWID
INTEGER STRING
NATURAL VARCHAR
NUMBER VARCHAR2
NUMERIC
POSITIVE DATE
REAL
SMALLINT BOOLEAN
2.3. Konwersja typów danych
Jawna konwersja typów:
| do
z | CHAR DATE NUMBER RAW ROWID
----------------------------------------------------------------------------------------------------------------------------------
CHAR | TO_DATE TO_NUMBER HEXTORAW CHARTOROWID
DATE | TO_CHAR
NUMBER | TO_CHAR TO_DATE
RAW | RAWTOHEX
ROWID | ROWIDTOCHAR
2.5. Bloki PL/SQL'a
PL/SQL jest blokowo zorientowanym językiem. Oznacza to, że programem PL/SQL są logiczne bloki, które mogą zawierać dowolną liczbę bloków zagnieżdżonych. Blok (podblok) pozwala grupować logicznie powiązane deklaracje i instrukcje. Deklaracje są lokalne dla bloku i przestają istnieć po zakończeniu wykonywania instrukcji bloku.
PL/SQL blok składa się z trzech części: opcjonalnej części deklaracji, wykonywalnej części i opcjonalnej części obsługi wyjątków.
[DECLARE
-- deklaracje]
BEGIN
-- instrukcje
[EXCEPTION
-- obsługa wyjątków]
END;
Bloki można zagnieżdżać w części wykonywalnej i części obsługi wyjątków bloku PL/SQL.
2.6. Zmienne i stałe
Zmienne i stałe należy deklarować w części deklaracji dowolnego bloku PL/SQL, podprogramu czy pakietu.
birthdate DATE;
emp_count SMALLINT := 0;
acct_id VARCHAR2(5) NOT NULL := 'AP001';
Użycie konstruktora NOT NULL wymaga zastosowania klauzuli inicjalizacji zmiennej lub stałej.
pi CONSTANT REAL := 3.14159;
radius REAL := 1;
area REAL := pi * radius**2;
Po słowie kluczowym CONSTANT należy podać typ stałej i zainicjalizować deklarowaną stałą. Deklarowane identyfikatory w bloku muszą być unikalne.
W deklaracjach nie można odwoływać się do niezadeklarowanych zmiennych i stałych. Również nie można wyliczać zmiennych i stałych po przecinku.
2.7. Atrybut %TYPE
Atrybut %TYPE dostarcza typ danych zmiennej, stałej lub kolumny tabeli.
credit REAL(7,2);
debit credit%TYPE;
Deklaracja przez %TYPE może zawierać klauzulę inicjalizacji.
balance NUMBER(7,2);
minimum_balance balance%TYPE := 10.00;
Użycie atrybutu %TYPE pozwala uwolnić kod od konieczności zmiany typu zmiennej, po zmianie typu bazowego. Jest on szczególnie użyteczny, gdy są deklarowane zmienne, których typ jest związany z typem kolumn tabel.
Konstruktora NOT NULL nie można używać w deklaracjach zmiennych z użyciem %TYPE.
2.8. Atrybut %ROWTYPE
Atrybut %ROWTYPE dostarcza typ reprezentujący wiersz tabeli lub perspektywy. Rekord przechowuje cały wiersz tabeli.
DECLARE
emp_rec emp%ROWTYPE;
CURSOR c1 IS SELECT deptno, dname, loc FROM dept;
dept_rec c1%ROWTYPE;
...
Kolumny wiersza odpowiadają polom rekordu przy zachowaniu zgodności nazw i typów. Dostęp do pól rekordu wymaga zastosowania notacji kropkowej.
IF emp_rec.deptno = 20 THEN ...
Deklaracja %ROWTYPE nie może zawierać klauzuli inicjalizacji. Mimo tego istnieją dwa sposoby przypisania wartości do wszystkich pól rekordu. Pierwszy polega na wykorzystaniu kursora a drugi na wykorzystaniu instrukcji SELECT ..INTO ...
2.9. Zakres identyfikatorów
Identyfikatory deklarowane w bloku PL/SQL są lokalne dla tego bloku a globalne dla bloków zagnieżdżonych. Jeżeli globalne identyfikatory zostaną powtórnie zadeklarowane w bloku zagnieżdżonym, to w celu odwołania się do identyfikatorów globalnych należy użyć kwalifikatora. Kwalifikatorem dla bloku jest etykieta umieszczana przed słowem kluczowym DECLARE.
<<outer>>
DECLARE
birthdate DATE;
BEGIN
...
DECLARE
birthdate DATE;
BEGIN
...
IF birthdate = outer.birthdate THEN
...
END IF;
END;
END outer;
3. Instrukcje kontroli sterowania
3.1. Instrukcje warunkowe
Dopuszcza się stosowanie trzech form instrukcji IF: IF-THEN, IF-THEN-ELSE, i IF-THEN-ELSIF.
Każda klauzula instrukcja IF musi zawierać przynajmniej jedną instrukcję wykonywalną. Może nią być instrukcja NULL dla spełnienia wymagań formalnych.
IF-THEN
IF warunek THEN
sekwencja_instrukcji;
END IF;
Sekwencja instrukcji jest wykonywana tylko wtedy, gdy warunek ma wartość TRUE. Jeżeli warunek ma wartość FALSE lub NULL, to jest wykonywana następna instrukcja po słowie kluczowym END IF.
IF-THEN-ELSE
IF warunek THEN
sekwencja_instrukcji1;
ELSE
sekwencja_instrukcji2;
END IF;
Sekwencja instrukcji w klauzuli ELSE jest wykonywana tylko wtedy, gdy warunek ma wartość FALSE lub NULL
Klauzule THEN i ELSE mogą zawierać konstrukcje IF.
IF-THEN-ELSIF
IF warunek1 THEN
sekwencja_instrukcji1;
ELSIF warunek2 THEN
sekwencja_instrukcji2;
ELSE
sekwencja_instrukcji3;
END IF;
Jeżeli pierwszy warunek ma wartość FALSE lub NULL, to klauzula ELSIF testuje kolejny warunek. Konstrukcja IF może zawierać dowolną liczbę klauzul ELSIF; końcowa klauzula ELSE jest opcjonalna. Jeżeli jakiś warunek ma wartość TRUE, to po wykonaniu sekwencji instrukcji tej klauzuli jest wykonywana następna instrukcja po słowie kluczowym END IF.
3.2. Pętle
Dopuszcza się stosowanie trzech form instrukcji LOOP : LOOP, WHILE-LOOP i FOR-LOOP.
LOOP
LOOP
sekwencja_instrukcji;
END LOOP;
Konstrukcja wymaga zastosowania instrukcji EXIT wewnątrz pętli.
WHILE-LOOP
WHILE warunek LOOP
sekwencja_instrukcji;
END LOOP;
Przed wykonaniem każdej iteracji jest wartościowany warunek. Jeżeli warunek ma wartość TRUE, to jest wykonywana sekwencja instrukcji. Jeżeli warunek ma wartość FALSE lub NULL, to jest wykonywana następna instrukcja po słowie kluczowym END LOOP.
FOR-LOOP
FOR counter IN [REVERSE] lower_bound..higher_bound LOOP
sekwencja_instrukcji;
END LOOP;
Zakres jest wartościowany tylko przy pierwszym wejściu do instrukcji FOR loop. Sekwencja instrukcji jest wykonywana dopóki licznik pętli będzie należał do zakresu. Po wykonaniu iteracji licznik pętli jest inkrementowany.
Jeżeli początek zakresu jest równy końcowi zakresu, to iteracja jest wykonywana jeden raz. Jeżeli początek zakresu jest większy od końca zakresu, to iteracja nie jest wykonywana i jest wykonywana następna instrukcja po słowie kluczowym END LOOP.
W celu ograniczenia zakresu pętli można użyć literałów, zmiennych lub wyrażeń pod warunkiem, że mogą zostać przeliczone.
j IN -5..5
k IN REVERSE first..last
step IN 0..TRUNC(high/low) * 2
code IN ASCII('A')..ASCII('J')
Licznik pętli może być wykorzystywany wewnątrz pętli.
3.3. Instrukcja pusta NULL
Instrukcja pusta przekazuje kontrolę do następnej instrukcji. Użycie instrukcji pustej zwiększa czytelność i przejrzystość.
...
EXCEPTION
WHEN ZERO_DIVIDE THEN
ROLLBACK;
WHEN VALUE_ERROR THEN
INSERT INTO errors VALUES ...
COMMIT;
WHEN OTHERS THEN
NULL;
END;
4. Interakcja z Oracle'm
PL/SQL pozwala używać wszystkich instrukcji SQL'a operujących na danych ( za wyjątkiem EXPLAIN PLAN), instrukcji kontroli transakcji, funkcji, pseudokolumn i operatorów.
4.1. SQL Funkcje
PL/SQL pozwala używać wszystkich funkcji SQL'a w tym również funkcji agregujących:
* AVG
* COUNT
* MAX
* MIN
* STDDEV
* SUM
* VARIANCE
Funkcji agregujących można używać tylko w instrukcjach SQL'owych, ale nie można używać w instrukcjach proceduralnych.
Postać odwołania do funkcji agregujących:
nazwa_funkcji([ALL | DISTINCT] wyr)
gdzie "wyr" jest wyrażeniem odwołującym się do jednej lub kilku kolumn. Jeżeli zostanie umieszczone słowo ALL (domyślnie), to funkcja agregująca obejmie wszystkie wartości w kolumnie. Jeżeli zostanie umieszczone słowo DISTINCT, to funkcja agregująca obejmie unikalne wartości w kolumnie
Funkcja COUNT pozwala wyspecyfikować znak '*', wynikiem czego będzie liczba wierszy tabeli.
4.2. SQL Pseudokolumny
PL/SQL rozpoznaje następujące pseudokolumny SQL'owe, które zwracają specyficzne wartości:
* CURRVAL - bieżący numer sekwencji
* LEVEL - poziom węzła w strukturze drzewa
* NEXTVAL - następny numer sekwencji
* ROWID - adres wiersza
* ROWNUM - liczba wierszy wybranych przez zapytanie
Do pseudokolumn można odwoływać się w instrukcjach SQL'owych, można wybierać wartości, ale nie można wstawiać, aktualizować i usuwać wartości.
4.3. SQL Operatory
PL/SQL pozwala używać wszystkich operatorów relacji, zbiorów i wierszy w instrukcjach SQL'owych.
Operatory relacji są używane w klauzuli WHERE wyliczając wartość wyrażenia, które może mieć wartość TRUE, FALSE lub NULL. Istnieje możliwość składania warunków używając w tym celu operatorów logicznych AND, OR lub NOT.
ALL - porównuje wartość do każdej wartości z listy lub podzapytania i ma wartość TRUE jeżeli wszystkie poszczególne porównania mają wartość TRUE.
ANY, SOME - porównują wartość do każdej wartości z listy lub podzapytania i ma wartość TRUE jeżeli jedno z porównań miało wartość TRUE.
BETWEEN - testuje czy wartość znajduje się wewnątrz przedziału.
EXISTS - zwraca TRUE jeżeli wynikiem podzapytania jest przynajmniej jeden wiersz
IN - testuje obecność w zbiorze
IS NULL - testuje nulls
LIKE - testuje czy łańcuch pasuje do wzorca
Operatory zbiorów składają wynik z dwóch zapytań
INTERSECT - zwraca wszystkie unikalne wiersze z obu zapytań
MINUS - zwraca wszystkie unikalne wiersze z pierwszego zapytania
UNION - zwraca wszystkie unikalne wiersze z drugiego zapytania
UNION ALL - zwraca wszystkie wiersze z drugiego zapytania ze wszystkimi powtórzeniami
Operatory wierszy odwołują się do poszczególnych wierszy.
ALL - wszystkie wiersze
DISTINCT - unikalne wiersze
PRIOR - odwołuje się do rodzica aktualnego wiersza.
4.4. Kursory
Oracle tworzy robocze obszary nazywane "private SQL areas" dla wykonywania instrukcji SQL'a i przechowywania informacji o procesach. Konstrukcja PL/SQL nazywana "kursorem" pozwala utworzyć i wykorzystać prywatny obszar SQL'a. Rozróżnia się dwa rodzaje kursorów: jawne i niejawne.
PL/SQL niejawnie deklaruje kursor dla wszystkich instrukcji manipulowania danymi(DMS), włączając zapytania zwracające tylko jeden wiersz. Dla zapytań zwracających więcej niż jeden wiersz można jawnie zadeklarować kursor przetwarzający indywidualnie wiersze.
Każdy kursor jawnie zdefiniowany ma cztery atrybuty: %NOTFOUND, %FOUND, %ROWCOUNT i %ISOPEN. Po dołączeniu do nazwy kursora nazwy atrybutu można uzyskać informację o wykonaniu wielowierszowego zapytania. Niejawny kursor SQL ma te same atrybuty co jawny kursor. Pozwalają one uzyskać informację o wykonaniu instrukcji INSERT, UPDATE, DELETE i SELECT INTO.
Atrybutów kursorów można używać w instrukcjach proceduralnych ale nie w instrukcjach SQL.
4.4.1. Jawne kursory
Zbiór wierszy zwróconych przez wielowierszowe zapytanie nazywa się "aktywnym zbiorem". Jego rozmiar odpowiada liczbie wierszy spełniających kryterium wyszukiwania. Jawny kursor wskazuje bieżący wiersz w aktywnym zbiorze. To pozwala programowi przetwarzać pojedynczy wiersz.
Kursor może być kontrolowany przez trzy rozkazy: OPEN, FETCH, i CLOSE. Najpierw należy zainicjować kursor rozkazem OPEN, który identyfikuje aktywny zbiór. Potem, można używając rozkazu FETCH pobierać kolejno wiersze ze zbioru. Po przetworzeniu ostatniego wiersza należy zwolnić kursor poleceniem CLOSE.
Jawne kursory mogą zawierać parametry.
CURSOR nazwa [ (parametr [, parametr, ...]) ] IS
SELECT ...
gdzie "parametr" wymaga następującej deklaracji
nazwa_zmiennej [IN] typ [{:= | DEFAULT wartość]
Zakres parametrów kursora jest lokalny co oznacza, że można odwoływać się do parametrów tylko w sekcji deklaracji kursora. Wartości parametrów kursora są kojarzone w zapytaniu w momencie otwarcia kursora.
4.4.2. Niejawne kursory
Oracle niejawnie otwiera kursor do przetwarzania każdej instrukcji SQL'a nie połączonej z jawnie zadeklarowanym kursorem. PL/SQL pozwala odwoływać się do ostatniego niejawnego kursora jak do kursora SQL. Tym samym można używać atrybutów kursora w celu pozyskania informacji o ostatnio wykonanej instrukcji SQL.
Przed otwarciem kursora SQL atrybuty kursora niejawnego są ustawiane na wartość NULL.
4.4.3. Instrukcja OPEN
Instrukcja OPEN wykonuje zapytanie skojarzone z jawnie zadeklarowanym kursorem. Otwarcie kursora wykonuje zapytanie i identyfikuje aktywny zbiór, który zawiera wiersze spełniające kryterium wyszukiwania.
Dla kursorów zadeklarowanych z użyciem klauzuli FOR UPDATE, instrukcja OPEN blokuje te wiersze.
OPEN c1;
Przekazywanie parametrów
Przykład
CURSOR c1 (my_ename CHAR, my_comm NUMBER) IS SELECT ...
instrukcje otwierające kursor:
OPEN c1('ATTLEY', 300);
OPEN c1(employee_name, 150);
OPEN c1('THURSTON', my_comm);
Parametrom formalnym zadeklarowanym z wartościami domyślnymi nie muszą odpowiadać parametry aktualne.
Każdy parametr aktualny musi mieć typ danych kompatybilny z typem odpowiadającego parametru formalnego.
4.4.4. Instrukcja FETCH
Instrukcja FETCH pobiera kolejno wiersze z aktywnego zbioru. Za każdym razem wykonywania instrukcji FETCH kursor jest przesuwany do następnego wiersza aktywnego zbioru.
Typowy sposób użycia instrukcji FETCH:
OPEN c1;
LOOP
FETCH c1 INTO my_record;
EXIT WHEN c1%NOTFOUND;
-- przetwarzanie danych
END LOOP;
4.4.5. Instrukcja CLOSE
Instrukcja CLOSE zwalnia kursor a aktywny zbiór przestaje być zdefiniowany.
CLOSE c1;
Zaraz po zamknięciu kursora można otworzyć go ponownie. Jakakolwiek operacja na zamkniętym kursorze zgłasza predefiniowany wyjątek INVALID_CURSOR.
4.4.6. Atrybut %NOTFOUND
Jawne kursory
Przed pierwszym pobraniem z aktywnego zbioru %NOTFOUND ma wartość NULL. Jeżeli ostatnie pobranie wiersza nie powiodło się, to %NOTFOUND ma wartość TRUE.
LOOP
FETCH c1 INTO my_ename, my_deptno;
EXIT WHEN c1%NOTFOUND;
...
END LOOP;
Jeżeli kursor nie jest otwarty odwołanie do atrybutu %NOTFOUND zgłosi predefiniowany wyjątek INVALID_CURSOR.
Niejawne kursory
%NOTFOUND ma wartość TRUE jeżeli INSERT, UPDATE, or DELETE nie zadziała na żadnym wierszu lub SELECT INTO nie zwróci żadnego wiersza. Poza tymi przypadkami %NOTFOUND ma wartość FALSE.
UPDATE emp SET sal = sal * 1.05 WHERE empno = my_empno;
IF SQL%NOTFOUND THEN -- aktualizacji nie powiodła się
INSERT INTO temp VALUES (...);
END IF;
Jeżeli SELECT INTO nie zwróci wiersza, to predefiniowany wyjątek NO_DATA_FOUND jest zgłaszany bez względu na to czy jest sprawdzany %NOTFOUND w następnej linii, czy nie.
W takiej sytuacji %NOTFOUND jest użyteczny w programie obsługi wyjątków OTHERS. Zamiast kodować program obsługi NO_DATA_FOUND, można sprawdzić zgłoszenie wyjątku %NOTFOUND.
EXCEPTION
WHEN OTHERS THEN
IF SQL%NOTFOUND THEN -- sprawdzenie 'no data found'
...
END IF;
...
END;
4.4.7. Atrybut %FOUND
Jawne kursory
%FOUND jest logicznym przeciwieństwem %NOTFOUND. Po otwarciu jawnego kursora a przed pierwszym pobraniem %FOUND ma wartość NULL.
LOOP
FETCH c1 INTO my_ename, my_deptno;
IF c1%FOUND THEN -- pobranie udane
INSERT INTO temp VALUES (...);
ELSE -- pobranie nieudane
EXIT;
END IF;
...
END LOOP;
Niejawne kursory
%FOUND jest logicznym przeciwieństwem %NOTFOUND.
DELETE FROM temp_emp WHERE empno = my_empno;
IF SQL%FOUND THEN -- usunięcie udane
INSERT INTO emp VALUES (my_empno, my_ename, ...);
END IF;
4.4.8. Atrybut %ROWCOUNT
Jawne kursory
Otwarcie jawnego kursora zeruje atrybut %ROWCOUNT.
Przed pierwszym pobraniem wiersza %ROWCOUNT zwraca zero. Następnie zwraca liczbę wierszy dotąd pobranych. Licznik jest inkrementowany jeżeli ostatnie pobranie wiersza zakończyło się pomyślnie.
LOOP
FETCH c1 INTO my_ename, my_deptno;
IF c1%ROWCOUNT > 10 THEN
...
END IF;
...
END LOOP;
Niejawne kursory
%ROWCOUNT zwraca liczbę wierszy na których zadziałała instrukcja INSERT, UPDATE, DELETE lub zwróconych przez instrukcję SELECT INTO.
DELETE FROM emp WHERE ...
IF SQL%ROWCOUNT > 10 THEN
...
END IF;
Jeżeli SELECT INTO zwraca więcej niż jeden wiersz, to jest zgłaszany predefiniowany wyjątek TOO_MANY_ROWS i %ROWCOUNT jest ustawiany na 1, a nie na aktualną liczbę wierszy.
4.4.9. Atrybut %ISOPEN
Jawne kursory
%ISOPEN ma wartość TRUE jeżeli kursor jest otwarty, w przeciwnym razie ma wartość FALSE.
IF c1%ISOPEN THEN -- czy kursor otwarty
...
ELSE -- kursor zamknięty
OPEN c1;
END IF;
Niejawne kursory
Oracle automatycznie zamyka kursor SQL po wykonaniu instrukcji SQL. Wynikiem czego %ISOPEN zawsze ma wartość FALSE.
4.4.10. Upakowane kursory
Można oddzielić specyfikację kursora od ciała przez wykorzystanie pakietu z klauzulą RETURN.
CREATE PACKAGE emp_actions AS
/* Deklaracja specyfikacji kursora. */
CURSOR c1 RETURN emp%ROWTYPE;
...
END emp_actions;
CREATE PACKAGE BODY emp_actions AS
/* Definicja ciała kursora. */
CURSOR c1 RETURN emp%ROWTYPE
SELECT * FROM emp WHERE sal > 3000;
...
END emp_actions;
4.4.11. Kursor pętli FOR
Kursor FOR loop niejawnie deklaruje indeks pętli jako %ROWTYPE rekord, otwiera kursor, kolejno pobiera wiersze aktywnego zbioru podstawiając do rekordu, i zamyka kursor po zakończeniu przetwarzania.
DECLARE
salary_total REAL := 0.0;
CURSOR c1 IS SELECT ename, sal, hiredate, deptno FROM emp;
...
BEGIN
FOR emp_rec IN c1 LOOP
...
salary_total := salary_total + emp_rec.sal;
END LOOP;
...
END;
Dopuszcza się używanie aliasów dla komponentów instrukcji select.
CURSOR c1 IS
SELECT empno, sal+NVL(comm,0) wages, job FROM ...
4.4.12. Przekazywanie parametrów
DECLARE
CURSOR c1 (dnum NUMBER) IS
SELECT sal, comm FROM emp WHERE deptno = dnum;
...
BEGIN
FOR emp_rec IN c1(20) LOOP
...
END LOOP;
...
END;
4.4.13. Klauzula ORDER BY alias
DECLARE
CURSOR c1 IS
SELECT empno, ename, sal+comm wages
FROM emp
WHERE job = 'SALESPERSON'
ORDER BY wages;
...
4.5. Instrukcje kontroli transakcji
4.5.1. Zastosowanie instrukcji COMMIT
COMMIT potwierdza zmiany wykonane w bieżącej transakcji. Dopóki nie zostaną potwierdzone zmiany pozostali użytkownicy nie mają dostępu do zmienionych danych. Widzą dane przed zmianami.
BEGIN
...
UPDATE accounts SET bal = my_bal - debit
WHERE acctno = my_acctno;
...
UPDATE accounts SET bal = my_bal + credit
WHERE acctno = my_acctno;
COMMIT;
END;
Instrukcja COMMIT odblokowuje wszystkie wiersze. Również usuwa zaznaczone punkty od momentu ostatniego COMMIT czy ROLLBACK.
4.5.2. Zastosowanie instrukcji ROLLBACK
Instrukcja ROLLBACK jest przeciwieństwem instrukcji COMMIT. ROLLBACK kończy bieżącą transakcję i wycofuje zmiany powstałe od momentu rozpoczęcia transakcji. Instrukcja ROLLBACK jest przydatna z dwóch względów. Po pierwsze po skasowaniu wiersza z tabeli można przy użyciu instrukcji ROLLBACK odzyskać skasowany wiersz. Po drugie, ROLLBACK jest przydatny kiedy rozpoczęta transakcja nie może zostać zakończona z powodu zgłoszenia wyjątku czy błędu wykonania instrukcji SQL. W takiej sytuacji ROLLBACK pozwala wrócić do poprawnego stanu przed rozpoczęciem transakcji.
DECLARE
emp_id INTEGER;
...
BEGIN
SELECT empno, ... INTO emp_id, ... FROM new_emp WHERE ...
...
INSERT INTO emp VALUES (emp_id, ...);
INSERT INTO tax VALUES (emp_id, ...);
INSERT INTO pay VALUES (emp_id, ...);
...
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
ROLLBACK;
...
END;
4.5.3. Zastosowanie instrukcji SAVEPOINT
SAVEPOINT nazywa i zaznacza bieżącą pozycję w przetwarzaniu transakcji. Użycie ROLLBACK TO powoduje wycofanie zmian do zaznaczonej pozycji.
DECLARE
emp_id emp.empno%TYPE;
BEGIN
...
UPDATE emp SET ... WHERE empno = emp_id;
DELETE FROM emp WHERE ...
...
SAVEPOINT do_insert;
INSERT INTO emp VALUES (emp_id, ...);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
ROLLBACK TO do_insert;
END;
Po wycofaniu zmian wszystkie pozycje, które były zaznaczone później niż punkt, do którego zostały wycofane zmiany są usuwane. Punkt, do którego nastąpiło cofnięcie nie zostaje usunięty. W celu usunięcia takiego punktu należy wykonać instrukcję ROLLBACK lub COMMIT, która jednocześnie usuwa wszystkie punkty.
BEGIN
...
SAVEPOINT my_point;
UPDATE emp SET ... WHERE empno = emp_id;
...
SAVEPOINT my_point; -- przesunięcie punktu my_point
INSERT INTO emp VALUES (emp_id, ...);
...
EXCEPTION
WHEN OTHERS THEN
ROLLBACK TO my_point;
END;
Domyślnie, liczba aktywnych punktów w sesji jest ograniczona do 5.
4.5.4. Klauzula FOR UPDATE
DECLARE
CURSOR c1 IS SELECT empno, sal FROM emp
WHERE job = 'SALESMAN' AND comm > sal FOR UPDATE;
Klauzula FOR UPDATE wskazuje, że wiersze z aktywnego zbioru będą aktualizowane lub usuwane. Otwarcie kursora blokuje wszystkie wiersze aktywnego zbioru. Wiersze zostają odblokowane po użyciu instrukcji COMMIT .
DECLARE
CURSOR c1 IS SELECT empno, job, sal FROM emp FOR UPDATE;
...
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO ...
...
UPDATE emp SET sal = new_sal WHERE CURRENT OF c1;
END LOOP;
...
4.6. Wyzwalacze
Wyzwalacze są zapamiętanymi programami PL/SQL skojarzonymi z wyspecyfikowanymi tabelami. Wyzwalacze są wykonywane automatycznie w przeciwieństwie do podprogramów, które wymagają jawnego uruchomienia.
Dopuszcza się stosowanie do 12 wyzwalaczy na tabelę. Aby utworzyć wyzwalacz należy posiadać przywilej CREATE TRIGGER i ALTER na skojarzonej tabeli lub ALTER ANY TABLE.
4.6.1. Tworzenie wyzwalacza
Wyzwalacz składa się z trzech części: zdarzenia, opcjonalnego konstruktora i akcji.
CREATE TRIGGER reorder
/* zdarzenie*/
AFTER UPDATE OF qty_on_hand ON inventory -- tabela
FOR EACH ROW
/* konstruktor */
WHEN (new.reorderable = 'T')
BEGIN
/* akcje */
IF :new.qty_on_hand < :new.reorder_point THEN
INSERT INTO pending_orders
VALUES (:new.part_no, :new.reorder_qty, SYSDATE);
END IF;
END;
Nazwa po klauzuli ON identyfikuje tabelę. Zdarzenie specyfikuje kiedy należy wykonać akcje. Słowo kluczowe AFTER specyfikuje kiedy należy wykonać akcje FOR EACH ROW oznacza, że wyzwalacz jest wykonywany dla każdego wiersza jeżeli zostanie spełniony warunek klauzuli WHEN. Przedrostek ":new" jest odwołaniem do nowej wartości kolumny. Można również używać przedrostka ":old".
CREATE TRIGGER check_salary
BEFORE INSERT OR UPDATE OF sal, job ON emp
FOR EACH ROW
WHEN (new.job != 'PRESIDENT')
DECLARE
minsal NUMBER;
maxsal NUMBER;
BEGIN
/* Get salary range for a given job from table sals. */
SELECT losal, hisal INTO minsal, maxsal FROM sals
WHERE job = :new.job;
/* If salary is out of range, increase is negative, *
* or increase exceeds 10%, raise an exception. */
IF (:new.sal < minsal OR :new.sal > maxsal) THEN
raise_application_error(-20225, 'Salary out of range');
ELSIF (:new.sal < :old.sal) THEN
raise_application_error(-20230, 'Negative increase');
ELSIF (:new.sal > 1.1 * :old.sal) THEN
raise_application_error(-20235, 'Increase exceeds 10%');
END IF;
END;
4.6.2. Rekompilacja
ALTER TRIGGER nazwa COMPILE;
4.6.3. Modyfikacja
CREATE OR REPLACE TRIGGER nazwa ... lub
DROP TRIGGER a następnie CREATE TRIGGER nazwa ...
4.6.4. Włączenie/Wyłączenie
ALTER TRIGGER nazwa ENABLE;
ALTER TRIGGER nazwa DISABLE;
Wyłączenie lub włączenie wszystkich wyzwalaczy związanych z tabelą:
ALTER TABLE nazwa_tabeli DISABLE ALL TRIGGERS;
ALTER TABLE nazwa_tabeli ENABLE ALL TRIGGERS;
4.6.5. Informacja o wyzwalaczach
USER_TRIGGERS, ALL_TRIGGERS, DBA_TRIGGERS
5. Obsługa błędów
5.1. Wyjątki
PL/SQL udostępnia prosty sposób obsługi wyjątków predefiniowanych i zdefiniowanych przez użytkownika. Kiedy zostanie zgłoszony wyjątek następuje przerwanie wykonywania programu i przejście do programu obsługi wyjątku. Predefiniowane wyjątki są zgłaszane niejawnie przez system a wyjątki zdefiniowane wymagają jawnego zgłoszenia przez klauzulę RAISE.
Wyjątki mogą być definiowane w części deklaracji bloku PL/SQL, podprogramu czy wyzwalacza. W części wykonywalnej należy testować pojawienie się wyjątku.
PROCEDURE calc_bonus (emp_id INTEGER, bonus OUT REAL) IS
my_sal NUMBER(7,2);
my_comm NUMBER(7,2);
comm_missing EXCEPTION; -- deklaracja wyjątku
BEGIN
SELECT sal, comm INTO my_sal, my_comm FROM emp
WHERE empno = emp_id;
IF my_comm IS NULL THEN
RAISE comm_missing; -- zgłoszenie wyjątku
ELSE
bonus := (my_sal * 0.05) + (my_comm * 0.15);
END IF;
EXCEPTION -- rozpoczęcie obsługi wyjątków
WHEN comm_missing THEN
-- obsługa błędu
WHEN OTHERS THEN -- obsługa pozostałych wyjątków
...
END calc_bonus;
Opcjonalna zmienna OTHERS obejmuje wszystkie niewyspecyfikowane wyjątki.
5.2. Deklaracja wyjątków
DECLARE
past_due EXCEPTION;
acct_num NUMBER(5);
BEGIN
...
5.3. Zakres działania wyjątków
Nie można zadeklarować wyjątku dwukrotnie w tym samym bloku, ale można w dwóch różnych blokach. Wyjątki deklarowane w bloku są lokalne, natomiast dla bloków zagnieżdżonych są globalne.
Zadeklarowanie wyjątku w bloku zagnieżdżonym przysłania deklarację globalnego wyjątku. Odwołanie do wyjątku z bloku nadrzędnego wymaga następującej konstrukcji:
etykieta_bloku.nazwa_wyjątku
DECLARE
past_due EXCEPTION;
acct_num NUMBER;
BEGIN
...
---------------- początek podbloku ----------------
DECLARE
past_due EXCEPTION; -- powtórzenie deklaracji
acct_num NUMBER;
BEGIN
...
IF ... THEN
RAISE past_due; -- zgłoszenie wyjątku
END IF;
...
END;
-------------------koniec podbloku -------------------
EXCEPTION
WHEN past_due THEN -- zgłoszony wyjątek nie jest obsługiwany
...
END;
5.4. Obsługa wyjątków
Po zgłoszeniu wyjątku następuje przejście do programu obsługi wyjątku.
...
EXCEPTION
WHEN ... THEN
-- obsługa błędu
WHEN ... THEN
-- obsługa błędu
WHEN OTHERS THEN
-- obsługa pozostałych błędów
END;
Po klauzuli WHEN należy podać nazwę wyjątku, następnie po słowie THEN umieścić instrukcje do wykonania.
5.5. Predefiniowane wyjątki
Nazwa wyjątku Błąd
--------------------------------------------------------------------------
CURSOR_ALREADY_OPEN ORA-06511
DUP_VAL_ON_INDEX ORA-00001
INVALID_CURSOR ORA-01001
INVALID_NUMBER ORA-01722
LOGIN_DENIED ORA-01017
NO_DATA_FOUND ORA-01403
NOT_LOGGED_ON ORA-01012
PROGRAM_ERROR ORA-06501
STORAGE_ERROR ORA-06500
TIMEOUT_ON_RESOURCE ORA-00051
TOO_MANY_ROWS ORA-01422
TRANSACTION_BACKED_OUT ORA-00061
VALUE_ERROR ORA-06502
ZERO_DIVIDE ORA-01476
Opis predefiniowanych wyjątków można znaleźć w dokumentacji PL/SQL'a.
5.6. Redeklaracja predefiniowanych wyjątków
W celu odwołania do wyjątku predefiniowanego, przesłoniętego przez użytkownika deklaracją tego wyjątku należy zastosować notację przedstawioną poniżej.
...
EXCEPTION
WHEN invalid_number OR STANDARD.INVALID_NUMBER THEN
-- handle the error
...
END;
5.7. Pragma EXCEPTION_INIT
Do obsługi nienazwanych wewnętrznych błędów należy użyć sekcji OTHERS lub pragmy EXCEPTION_INIT.
Predefiniowana pragma EXCEPTION_INIT umożliwia skojarzenie kodu błędu z nazwą wyjątku, co z koleji umożliwia obsługę wyjątku w części obsługi wyjątków.
PRAGMA EXCEPTION_INIT(nazwa_wyjątku, Oracle_kod_błędu);
gdzie "nazwa_wyjątku" jest nazwą wcześniej zadeklarowanego wyjątku. Pragma musi zanleźć się w dowolnym miejscu części deklaracji po zadeklarowaniu wyjątku.
DECLARE
insufficient_privileges EXCEPTION;
PRAGMA EXCEPTION_INIT(insufficient_privileges, -1031);
BEGIN
...
EXCEPTION
WHEN insufficient_privileges THEN
-- obsługa błędu
...
END;
5.8. Instrukcja RAISE
PL/SQL bloki i podprogramy powinny zgłaszać wyjątek jeżeli powstały błąd uniemożliwia normalne zakończenie programu. Można również zgłaszać jawnie predefiniowane wyjątki.
DECLARE
out_of_stock EXCEPTION;
number_on_hand NUMBER(4);
BEGIN
...
IF number_on_hand < 1 THEN
RAISE out_of_stock;
END IF;
...
EXCEPTION
WHEN out_of_stock THEN
-- obsługa błędu
END;
5.9. Propagacja wyjątków
Po zgłoszeniu wyjątku, jeżeli PL/SQL nie może znaleźć sekcji obsługi w bieżącym bloku, to wyjątek jest propagowany na zewnątrz. Propagacja trwa do momentu znalezienia sekcji obsługi błędu lub wygenerowania błędu w przypadku braku obsługi wyjątku.
DECLARE
...
BEGIN
...
---------------- początek podbloku ----------------
DECLARE
past_due EXCEPTION;
BEGIN
...
IF ... THEN
RAISE past_due;
END IF;
...
END;
------------------- koniec podbloku ----------------
...
EXCEPTION
...
WHEN OTHERS THEN
ROLLBACK;
END;
5.10. Przekazanie zgłoszenia wyjątku
Można stosować przekazywanie zgłoszenia wyjątku w sposób jawny.
DECLARE
out_of_balance EXCEPTION;
BEGIN
...
---------------- początek podbloku ----------------
BEGIN
...
IF ... THEN
RAISE out_of_balance; -- zgłoszenie wyjątku
END IF;
...
EXCEPTION
WHEN out_of_balance THEN
-- obsługa wyjątku
RAISE; -- propagacja aktualnego wyjątku
...
END;
------------------- koniec podbloku -------------------
EXCEPTION
WHEN out_of_balance THEN
-- obsługa błędu
...
END;
5.11. Zastosowanie SQLCODE i SQLERRM
W programie obsługi wyjątków można używać funkcji SQLCODE i SQLERRM do sprawdzenia błędu i wysłania komunikatu o błędzie.
DECLARE
msg CHAR(100);
BEGIN
FOR num IN 1..9999 LOOP
msg := SQLERRM(num); -- może być SQLERRM(-num)
INSERT INTO errors VALUES (msg);
END LOOP;
END;
Nie można używać funkcji SQLCODE lub SQLERRM bezpośrednio w instrukcji SQL.
6. Podprogramy
6.1. Podprogramy
Podprogramy są nazwanymi blokami PL/SQL'a, które mogą pobierać parametry i być wykonywane. Rozróżnia się dwa typy podprogramów: procedury i funkcje. Budowa podprogramów jest taka jak bloków PL/SQL'a.
PROCEDURE debit_account (acct_id INTEGER, amount REAL) IS
old_balance REAL;
new_balance REAL;
overdrawn EXCEPTION;
BEGIN
SELECT bal INTO old_balance FROM accts
WHERE acctno = acct_id;
new_balance := old_balance - amount;
IF new_balance < 0 THEN
RAISE overdrawn;
ELSE
UPDATE accts SET bal = new_balance
WHERE acctno = acct_id;
END IF;
EXCEPTION
WHEN overdrawn THEN
...
END debit_account;
6.2. Procedury
Procedura jest podprogramem, który wykonuje określoną akcję.
PROCEDURE nazwa [ (parametr [, parametr , ...]) ] IS
[deklaracje lokalne]
BEGIN
instrukcje
[EXCEPTION
obsługa błędów]
END [nazwa ];
gdzie "parametr" ma następującą składnię:
nazwa_zmiennej [IN | OUT | IN OUT] typ [{:= | DEFAULT wartość]
Procedura składa się z części specyfikacji i ciała.
Specyfikacja procedury rozpoczyna się słowem kluczowym PROCEDURE i kończy się nazwą procedury lub listą parametrów.
Ciało procedury rozpoczyna się słowem kluczowym IS i kończy się słowem kluczowym END, po którym może pojawić się opcjonalna nazwa procedury.
PROCEDURE raise_salary (emp_id INTEGER, increase REAL) IS
current_salary REAL;
salary_missing EXCEPTION;
BEGIN
SELECT sal INTO current_salary FROM emp
WHERE empno = emp_id;
IF current_salary IS NULL THEN
RAISE salary_missing;
ELSE
UPDATE emp SET sal = sal + increase
WHERE empno = emp_id;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO emp_audit VALUES (emp_id, 'No such number');
WHEN salary_missing THEN
INSERT INTO emp_audit VALUES (emp_id, 'Salary is null');
END raise_salary;
6.3. Funkcje
Funkcja jest podprogramem, który wylicza wartość funkcji. Funkcje i procedury mają taką samą strukturę, z wyjątkiem tego, że funkcja zawiera klauzulę RETURN. Klauzula RETURN określa typ zwracanej wartości. We ciele funkcji należy umieścić instrukcję RETURN z wartością, która ma być zwrócona.
FUNCTION nazwa [ (parametr [, parametr, ...]) ] RETURN typ IS
[deklaracje lokalne]
BEGIN
instrukcje
[EXCEPTION
obsługa błędów]
END [nazwa ];
gdzie "parametr" ma następującą składnię:
nazwa_zmiennej [IN | OUT | IN OUT] typ [{:= | DEFAULT wartość]
Wywołania funkcji w bloku PL/SQL'a lub podprogramie mogą pojawić się w proceduralnych instrukcjach, ale nie w instrukcjach SQL'a.
DECLARE
empnum INTEGER;
...
FUNCTION bonus (emp_id INTEGER) RETURN REAL IS
BEGIN ... END bonus;
BEGIN
...
INSERT INTO payroll
VALUES (empnum, ..., bonus(empnum)); -- nieprawidłowe wywołanie
END;
6.4. Instrukcja RETURN
Instrukcja RETURN natychmiast kończy wykonywanie podprogramu i zwraca sterowanie do miejsca wywołania. Nie należy mylić instrukcji RETURN z klauzulą RETURN. Podprogram może zawierać kilka Instrukcji RETURN. W procedurach instrukcja RETURN nie może zawierać wyrażenia. Wystąpienie instrukcji
RETURN zwraca sterowanie do miejsca wywołania przed normalnym zakończeniem wykonywania procedury. W funkcjach instrukcja RRETURN musi zawierać wyrażenie, które jest wyliczane w chwili wykonania instrukcji. Funkcja musi zawierać przynajmniej jedną instrukcję RETURN.
FUNCTION balance (acct_id INTEGER) RETURN REAL IS
acct_bal REAL;
BEGIN
SELECT bal INTO acct_bal FROM accts WHERE acctno = acct_id;
RETURN acct_bal;
END balance;
6.5. Deklaracje zapowiadające
PL/SQL wymaga zadeklarowania identyfikatora przed jego użyciem. Nie wolno wywoływać procedury bez jej poprzedniej deklaracji. W celu umożliwienia PL/SQL dopuszcza stosowanie deklaracji zapowiadających, umożliwiając tym samym:
* definiowanie podprogramów w porządku alfabetycznym
* definiowanie rekursywnych podprogramów
* grup podprogramów w pakiecie.
Deklaracja zapowiadająca składa się ze specyfikacji podprogramu zakończonej średnikiem.
DECLARE
PROCEDURE calc_rating (...); -- deklaracja zapowiadająca
/* Definicje podprogramów w porządku alfabetycznym */
PROCEDURE award_bonus (...) IS
BEGIN
calc_rating(...);
...
END;
PROCEDURE calc_rating (...) IS
BEGIN
...
END;
...
Parametry formalne muszą znaleźć się deklaracji zapowiadającej jak i we właściwej definicji ciała podprogramu.
6.6. Upakowane podprogramy w pakietach
Deklaracje zapowiadające pozwalają grupować logicznie powiązane podprogramy w pakiecie. Specyfikacje podprogramów znajdują się w specyfikacji pakietu a definicji podprogramów w definicji pakietu, gdzie nie są widoczne w aplikacji.
PACKAGE emp_actions IS -- specyfikacja pakietu
PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...);
PROCEDURE fire_employee (emp_id NUMBER);
END emp_actions;
PACKAGE BODY emp_actions IS -- definicja pakietu
PROCEDURE hire_employee (empno NUMBER, ename CHAR, ...) IS
BEGIN
INSERT INTO emp VALUES (empno, ename, ...);
END hire_employee;
PROCEDURE fire_employee (emp_id NUMBER) IS
BEGIN
DELETE FROM emp WHERE empno = emp_id;
END fire_employee;
END emp_actions;
Można zdefiniować podprogramy bez umieszczania specyfikacji programu w specyfikacji pakietu, ale takie programy nie są dostępne poza ciałem definicji pakietu.
6.7. Przekazywanie parametrów aktualnych
Wywoływanie podprogramu wymaga podania parametrów aktualnych. Parametry aktualne mogą być podane przez zachowanie zgodności z kolejnością parametrów formalnych lub przez skojarzenie nazw parametrów aktualnych z formalnymi.
DECLARE
acct INTEGER;
amt REAL;
PROCEDURE credit (acctno INTEGER, amount REAL) IS ...
...
BEGIN
credit(acct, amt); -- notacja pozycyjna
credit(amount => amt, acctno => acct); -- notacja nazywana
credit(acctno => acct, amount => amt); -- notacja nazywana
credit(acct, amount => amt); -- notacja mieszana
...
END;
6.8. Tryby przekazywania parametrów
Tryby przekazywania parametrów definiują zachowanie parametrów formalnych. Rozróżnia się trzy tryby: IN (domyślny), OUT i IN OUT. Należy unikać używania trybu OUT i IN OUT w funkcjach z uwagi na konstrukcję funkcji.
6.8.1. Tryb IN
Parametr w trybie IN pozwala przekazać wartość do wywoływanego podprogramu. Wewnątrz programu taki parametr zachowuje się jak stała.
PROCEDURE debit_account (acct_id INTEGER, amount REAL) IS
minimum_purchase CONSTANT REAL := 10.0;
service_charge CONSTANT REAL := 0.50;
BEGIN
IF amount < minimum_purchase THEN
amount := amount + service_charge; -- niepoprawne
END IF;
...
Aktualny parametr odpowiadający formalnemu parametrowi w trybie IN może być stałą, literałem, zainicjowaną zmienną lub wyrażeniem.
W przeciwieństwie do trybu OUT i IN OUT, parametry w trybie IN mogą być zainicjowane wartościami domyślnymi.
6.8.2. Tryb OUT
Parametr w trybie OUT pozwala przekazać wartość na zewnątrz wywoływanego podprogramu. Wewnątrz programu taki parametr zachowuje się jak niezainicjowana zmienna.
PROCEDURE calc_bonus (emp_id INTEGER, bonus OUT REAL) IS
hire_date DATE;
BEGIN
SELECT sal * 0.10, hiredate INTO bonus, hire_date FROM emp
WHERE empno = emp_id;
IF MONTHS_BETWEEN(SYSDATE, hire_date) > 60 THEN
bonus := bonus + 500; -- błąd syntaktyczny
END IF;
...
Aktualny parametr odpowiadający formalnemu parametrowi w trybie OUT musi być zmienną.
Jeżeli podprogram zakończy się pomyślnie, to PL/SQL przypisze wartości parametrom aktualnym. Jeżeli podprogram zakończy się wystąpieniem niezdefiniowanego wyjątku, to PL/SQL nie przypisze żadnych wartości parametrom aktualnym.
6.8.3. Tryb IN OUT
Parametr w trybie IN OUT pozwala przekazać wartość do wywoływanego podprogramu i zwrócić wartość na zewnątrz wywoływanego podprogramu. Wewnątrz programu taki parametr zachowuje się zainicjowana zmienna.
PROCEDURE calc_bonus (emp_id INTEGER, bonus IN OUT REAL) IS
hire_date DATE;
bonus_missing EXCEPTION;
BEGIN
SELECT sal * 0.10, hiredate INTO bonus, hire_date FROM emp
WHERE empno = emp_id;
IF bonus IS NULL THEN
RAISE bonus_missing;
END IF;
IF MONTHS_BETWEEN(SYSDATE, hire_date) > 60 THEN
bonus := bonus + 500;
END IF;
...
EXCEPTION
WHEN bonus_missing THEN
...
END calc_bonus;
Aktualny parametr odpowiadający formalnemu parametrowi w trybie OUT musi być zmienną.
6.9. Wartości domyślne parametrów
Wartości domyślne parametrów mogą być związane tylko z parametrami formalnymi w trybie IN. Jeżeli parametr aktualny zostanie pominięty w wywołaniu podprogramu to odpowiadający parametr formalny przybierze wartość domyślną.
6.10. Tworzenie upakowanych podprogramów
Podprogramy można oddzielnie kompilować i przechowywać w bazie danych. Umożliwia to instrukcja CREATE PROCEDURE i CREATE FUNCTION wywołana interakcyjnie z SQL*Plus lub SQL*DBA.
CREATE PROCEDURE fire_employee (emp_id NUMBER) AS
BEGIN
DELETE FROM emp WHERE empno = emp_id;
END;
Syntaktyka przechowywanego podprogramu jest identyczna z syntaktyką podprogramu z wyjątkiem pojawienia się słowa kluczowego AS w miejsce IS.
Raz skompilowany i zapamiętany w repozytorium bazy danych, podprogram staje się obiektem bazy danych, który może być wykorzystywany przez aplikacje połączone z bazą danych.
Przechowywane podprogramy mogą być wywoływane z wyzwalaczy, innych przechowywanych podprogramów, czy interakcyjnie z SQL*Plus lub SQL*DBA.
SQL> EXECUTE fire_employee(7499);
SQL> BEGIN create_dept('MARKETING', 'NEW YORK'); END;
6.11. Informacja o upakowanych podprogramach
Następujące perspektywy zawierają informację o podprogramach i pakietach:
ALL_SOURCE, USER_SOURCE, DBA_SOURCE
USER_OBJECT_SIZE, DBA_OBJECT_SIZE
7. Błędy kompilacji upakowanych wyzwalaczy i podprogramów
Błędy kompilacji w przypadku tworzenia upakowanych wyzwalaczy lub podprogramów moą zostać wyświetlone przez:
- użycie polecenia SHOW ERRORS lub
- sięgnięcie do perspektyw
ALL_ERRORS, USER_ERRORS, DBA_ERRORS
8. Pakiet DBMS_OUTPUT
Pakiet DBMS_OUTPUT jest szczególnie użyteczny dla wyświetlania informacji w trakcie śledzenia wykony-wania bloków PL/SQL'a. W tym celu należy ustawić zmienną środowiskową poleceniem:
SET SERVEROUTPUT ON.
8.1. PUT, PUT_LINE, NEW_LINE
Procedury PUT i PUT_LINE umieszczają podany jako parametr tekst w buforze, po którym w przypadku użycia procedury PUT_LINE jest umieszczany znacznik końca linii. Procedura NEW_LINE umieszcza w buforze znacznik końca linii.
DBMS_OUTPUT.PUT_LINE('Total wages = ' || TO_CHAR(total_wages));
Dodatki
A. Wybrane polecania SQL*Plus'a
@ (znak)
Wykonanie wyspecyfikowanego skryptu.
@ nazwa_skryptu.[rozszerzenie]
Przy wykonaniu polecenia SQL*Plus szuka wyspecyfikowanego skryptu w bieżącym katalogu. Jeżeli skrypt nie znajduje się w bieżącym katalogu to w linii polecenia należy zapisać ścieżkę dostępu przed nazwą skryptu.
Polecenie @ nie umożliwia przekazywania parametrów do skryptu w odróżnieniu od polecenia START.
/ (znak)
Wykonanie polecenia SQL lub bloku PL/SQL zapamiętanego w buforze
CONNECT
Polecenia zalogowania do bazy
CONNECT użytkownik[/hasło][@baza]
@baza - reprezentuje tekst połączenia z bazą zgodny z wymaganiami stawianymi przez SQL*Net.
DEFINE
Definiuje zmienne znakowe i przypisuje im wartości lub prezentuje zmienne i ich wartości
DEFINE [zmienna]|[zmienna=tekst]
Podanie DEFINE zmienna powoduje wyświetlenie wartości zmiennej a pominięcie zmiennej powoduje wyświetlenie wartości wszystkich zmiennych. Odwołanie w poleceniach SQL do zmiennej przez &zmienna wymaga podania wartości w przypadku, gdy zmiennej nie została wcześniej przypisana wartość a odwołanie przez &&zmienna nie wymaga kolejnego podawania wartości dla zmiennej. W celu odwołania definicji zmiennej należy użyć polecenia UNDEFINE.
DISCONNECT
Potwierdza zmiany i wylogowuje aktualnego użytkownika
EXIT
Potwierdza zmiany i oddaje sterowania do systemu operacyjnego
GET
Wprowadza wyspecyfikowany skrypt do bufora SQL
GET skrypt [LIST|NOT LIST]
Podanie opcji LIST powoduje wylistowanie zawartości wczytanego skryptu.
HOST
Wykonanie polecenia systemu operacyjnego
HOST [polecenie]
Podanie polecenia HOST bez parametrów powoduje przejście do systemu operacyjnego. Powrót następuje po napisaniu polecenia EXIT.
RUN
Listuje i wykonuje polecenie SQL lub blok PL/SQL znajdujący się w buforze SQL'a
RUN
SAVE
Zapisuje zawartość bufora SQL do skryptu
SAVE skrypt [CRE|REP|APP]
Domyślnym rozszerzeniem skryptu jest '.SQL'. Opcje zapisu oznaczają odpowiednio utworzenie nowego zbioru, zastąpienie zawartości zbioru i dopisanie do zbioru.
SET
Definiuje aspekt bieżącej sesji w środowisku SQL*Plus'a
SET zmienna_systemowa parametry
Zmienne systemowe:
SHOW
Listuje wartości zmiennych systemowych środowiska SQL*Plus'a
SHOW opcja
Opcje:
zmienna_systemowa - jedna z nazw zmiennych systemowych.
ALL - wszystkie zmienne.
REL - numer wersji ORACLE RDBMS'a
USER - nazwa użytkownika.
START
Wykonuje zawartość skryptu
START skrypt [par1 par2 ...]
Umożliwia wykonanie zawartości skryptu z możliwością przekazywania parametrów. Parametry przekazywane do skryptu są kolejno podstawiane po zmienne &1, &2 i itd. Jeżeli parametr ma reprezentować wartość typu CHAR, to należy odwołanie do tego parametru zapisać w apostrofach np. '&1'.
UNDEFINE
Usunięcie zdefiniowanej zmiennej
UNDEFINE zmienna
Usuwa zmienne zdefiniowane poleceniem DEFINE lub pośrednio przez parametry polecenia START.
Spis treści
1. Wstęp