Wykład 9. Pakiety w języku PL/SQL

Podobne dokumenty
Pakiety podprogramów Dynamiczny SQL

Pakiety są logicznymi zbiorami obiektów takich jak podprogramy, typy, zmienne, kursory, wyjątki.

Język PL/SQL Pakiety podprogramów

Język PL/SQL. Rozdział 5. Pakiety podprogramów. Dynamiczny SQL

Oracle PL/SQL. Paweł Rajba.

Wyzwalacze. Anna Fiedorowicz Bazy danych 2

Język PL/SQL Procedury i funkcje składowane

Materiały. Technologie baz danych. Plan wykładu Kursory. Wykład 5: Kursory jawne. Podprogramy. Kursory jawne. Kursory niejawne

w PL/SQL bloki nazwane to: funkcje, procedury, pakiety, wyzwalacze

Bloki anonimowe w PL/SQL

Procedury i funkcje składowane

Procedury składowane. Funkcje vs. procedury Funkcja. Procedura. zazwyczaj ma parametry tylko typu IN; można wywoływać z poziomu

DECLARE <nazwa_zmiennej> typ [(<rozmiar> )] [ NOT NULL ] [ { := DEFAULT } <wartość> ];

1 Wprowadzenie do bloków nazwanych 1. 2 Parametry 2. 3 Procedury i funkcje 3. 4 Pakiety 6. 5 Podsumowanie Źródła 10

15. Funkcje i procedury składowane PL/SQL

PODSTAWY BAZ DANYCH 13. PL/SQL

ZASTOSOWANIE PROCEDUR, FUNKCJI I PAKIETÓW

DECLARE VARIABLE zmienna1 typ danych; BEGIN

Tworzenie raportów XML Publisher przy użyciu Data Templates

Zaawansowane bazy danych i hurtownie danych semestr I

Podprogramy. Rozdział 11 Procedury i funkcje składowane

Język PL/SQL. Rozdział 4. Procedury i funkcje składowane

Oracle PL/SQL. Paweł Rajba.

PL/SQL. Zaawansowane tematy PL/SQL

Wyzwalacz - procedura wyzwalana, składowana fizycznie w bazie, uruchamiana automatycznie po nastąpieniu określonego w definicji zdarzenia

E.14 Bazy Danych cz. 18 SQL Funkcje, procedury składowane i wyzwalacze

PL/SQL. Zaawansowane tematy PL/SQL

Procedury Funkcje Pakiety. Tworzenie procedury

Funkcje w PL/SQL Funkcja to nazwany blok języka PL/SQL. Jest przechowywana w bazie i musi zwracać wynik. Z reguły, funkcji utworzonych w PL/SQL-u

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Oracle PL/SQL. Paweł Rajba.

Bazy danych wykład dwunasty PL/SQL, c.d. Konrad Zdanowski ( Uniwersytet Kardynała Stefana Bazy danych Wyszyńskiego, wykładwarszawa)

Plan wykładu BAZY DANYCH II WYKŁAD 7. Pakiety. Zalety pakietów

Oracle11g: Programowanie w PL/SQL

Wstęp do programowania 2

Programowanie w SQL procedury i funkcje. UWAGA: Proszę nie zapominać o prefiksowaniu nazw obiektów ciągiem [OLIMP\{nr indeksu}] Funkcje użytkownika

Podstawy Programowania Obiektowego

Wyzwalacze. do automatycznego generowania wartości kluczy głównych. Składnia instrukcji tworzacej wyzwalacz

Oracle PL/SQL. Paweł Rajba.

Wykład 8: klasy cz. 4

Pakiety i interfejsy. Tomasz Borzyszkowski

Procedury wyzwalane. (c) Instytut Informatyki Politechniki Poznańskiej 1

Przykład 3 Zdefiniuj w bazie danych hurtownia_nazwisko przykładową funkcję użytkownika fn_rok;

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Kursory i wyjątki. (c) Instytut Informatyki Politechniki Poznańskiej 1

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Cheatsheet PL/SQL Andrzej Klusiewicz 1/9

Ada-95. Dariusz Wawrzyniak

Oracle11g: Wprowadzenie do SQL

Instrukcje SQL można podzielić na pięć kategorii, które zostały przedstawione w poniższej tabeli.

Dziedziczenie. Tomasz Borzyszkowski

Przykład 1: Funkcja jest obiektem, przypisanie funkcji o nazwie function() do zmiennej o nazwie funkcja1

Oracle10g: Programowanie w PL/SQL

Plan wykładu Projekt fizyczny bazy danych Wprowadzenie PL/SQL PL/SQL Cechy PL/SQL

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

OBSŁUGA WYJĄTKÓW. Mechanizm języka PL/SQL. Wyjątki:

Deklarowanie kursora

Delphi Laboratorium 3

Oracle PL/SQL. Paweł Rajba.

Plan wykładu BAZY DANYCH II WYKŁAD 2. Bloki. Struktura bloku

Materiały do laboratorium MS ACCESS BASIC

Oracle PL/SQL. Paweł Rajba.

Wykład 5: Klasy cz. 3

ORACLE (Wykład 1) aragorn.pb.bialystok.pl/~aonisko. Typy rozproszonych baz danych. Systemy klient-serwer. Klient-serwer: Przykład

1 Kursory 1. 2 Wyjątki Wyjątki predefiniowane Wyjątki niezdefiniowane wcześniej Definiowanie własnych wyjątków...

Deklarowanie kursora. CURSOR nazwa [ ( param1 typ1 [,param2 typ2]... ) ] [RETURN typ zwracany] IS zapytanie SQL;

Oracle Developer Suite. Budowa aplikacji użytkownika końcowego

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

Zaawansowane programowanie w języku C++ Klasy w C++

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Język PL/SQL. Rozdział 3. Obsługa błędów wykonania Wyjątki predefiniowane i użytkownika, zgłaszanie i obsługa wyjątków.

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

Programowanie obiektowe - 1.

Październik Instytut Informatyki Teoretycznej i Stosowanej Politechnika Częstochowska. Systemy baz danych - wykład III. dr inż.

Wstęp do programowania

Plan wykładu BAZY DANYCH II WYKŁAD 3. Zasięg zmiennych. Zasięg zmiennych

Przeciążanie operatorów

SQL w języku PL/SQL. 2) Instrukcje języka definicji danych DDL DROP, CREATE, ALTER, GRANT, REVOKE

BAZY DANYCH W APLIKACJACH SIECIOWYCH

Cele. Definiowanie wyzwalaczy

Używany kiedy pełna treść instrukcji SQL jest nieznana przed uruchomieniem programu.

Język PL/SQL. Rozdział 2. Kursory

1. Wyzwalacze BD (ang. triggers)

Klasy Obiekty Dziedziczenie i zaawansowane cechy Objective-C

Plan wykładu BAZY DANYCH II WYKŁAD 9. Dynamiczny SQL. Dynamiczny SQL

Plan. Formularz i jego typy. Tworzenie formularza. Co to jest formularz? Typy formularzy Tworzenie prostego formularza Budowa prostego formularza

Laboratorium nr 12. Temat: Struktury, klasy. Zakres laboratorium:

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Ćwiczenie 13 PL/SQL. Język PL/SQL procedury, funkcje, pakiety, wyzwalacze

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

W2 Wprowadzenie do klas C++ Klasa najważniejsze pojęcie C++. To jest mechanizm do tworzenia obiektów. Deklaracje klasy :

Plan wykładu PL/SQL. PL/SQL - historia TWORZENIE APLIKACJI BAZODANOWYCH

Modelowanie i Programowanie Obiektowe

Kursor jawny. Rozdział 10a Kursory. Deklarowanie kursora (1) Deklarowanie kursora (2)

PLAN WYKŁADU BAZY DANYCH PODSTAWOWE KWESTIE BEZPIECZEŃSTWA OGRANICZENIA DOSTĘPU DO DANYCH

Podstawy programowania skrót z wykładów:

Rozdział 4 KLASY, OBIEKTY, METODY

Instrukcja podwaja zarobki osób, których imiona zaczynają się P i dalsze litery alfabetu zakładamy, że takich osbób jest kilkanaście.

Wstęp do programowania

Transkrypt:

Wykład 9. Pakiety w języku PL/SQL Pakiety (ang. packages): podobnie jak podprogramy, zaliczamy do bloków nazwanych języka PL/SQL, zostały zaczerpnięty z języka ADA, lecz w stosunku do pakietu tego języka charakteryzuje się specyficznymi definicjami i zachowaniami, ogólnie rzecz ujmując, jest konstrukcją, która grupuje ze sobą logicznie powiązane elementy języka PL/SQL w jeden obiekt w tym ujęciu można stwierdzić, iż pakiet jest nazwaną sekcja deklaracji. stanowi wygodne rozwiązanie w języku PL/SQL, stanowiące pewien użyteczny mechanizm pozwalający na organizowanie kodu w taki sposób, aby umożliwić jego łatwiejsze rozwijanie i utrzymywanie. Elementami języka PL/SQL, które mogą być powiązane w jedną całość w ramach pakietu, mogą być: stałe, zmienne, kursory, wyjątki, procedury, funkcje, typy danych. W ramach pakietu te powyżej wymienione elementy języka PL/SQL mogą, choć nie muszą występować. Ponadto pakiet może zawierać dowolną liczbę poszczególnych elementów języka PL/SQL, które zostały powyżej wymienione, np. może zawierać dowolną liczbę procedur i funkcji. Korzyścią umieszczenia tych obiektów w pakiecie jest zapewnienie możliwości odwoływania się do nich z innych bloków PL/SQL. A zatem jednym z możliwych zastosowań pakietu jest możliwość zadeklarowania zmiennych globalnych PL/SQL w ramach jednej sesji bazy danych. Tworzenie i budowa pakietu Na ogół pakiety w języku PL/SQL składają się z dwóch oddzielnych części: specyfikacji (nagłówka), treści (ciała). Każda z tych dwóch części pakietu jest oddzielnie składowana w słowniku danych. Ogólnie rzecz ujmując, pakiet jest nazwaną sekcją deklaracji. Wszystkie obiekty, które mogą znajdować się w części deklaracji bloku, mogą znajdować się również w pakiecie. Celowo pakiet języka PL/SQL składa się z dwóch odrębnych obiektów (słownika). Taka budowa pakietu ma pozytywne konsekwencje, przede wszystkim jeśli chodzi o samo wykorzystanie pakietów w konkretnych zastosowaniach. Poniżej wymienione zostały pewne pozytywne cechy zastosowania pakietów, które są wynikiem takiej właśnie budowy pakietów: konserwacja oddzielając szczegóły implementacji od definicji, nie musimy rekompilować ani zmieniać programów, kiedy zmienia się ich implementacja. Jeśli ulega zmianie tzw. logika biznesowa procedury lub funkcji, zmianę tę można wdrożyć tylko na poziomie treści pakietu. W ten sposób odwoływanie się do programów pozostaje nienaruszone. bezpieczeństwo użytkowania wiąże się z możliwością ukrywania informacji. W razie konieczności zmiany struktury procedury lub funkcji umieszczonej w pakiecie, jak stwierdzono powyżej, odwoływanie się do tych podprogramów może pozostawać niezmienione. Dzięki temu pakiet jest bardziej bezpieczną strukturą, ponieważ 1

jego nagłówek się nie zmienia. Ponadto definiując prywatne obiekty w treści pakietu, ukryte one zostają przed innymi użytkownikami. Obiekty te pozostają obiektami prywatnymi danego pakietu. hermetyzacja i modularność powiązane w ramach pakietu obiekty zostają zhermetyzowane wewnątrz bazy danych jako pojedyncza jednostka składająca się z logiki aplikacji, co prowadzi również do modularności wydajność kiedy po raz pierwszy następuje odwołanie do spakowanego podprogramu, do pamięci ładowany jest cały pakiet. Zwiększa to wydajność, ponieważ następuje redukcja dyskowych operacji wejścia/wyjścia wynikających z kolejnych wywołań. Wśród deklaracji elementów języka PL/SQL w pakiecie wyróżniamy: deklaracje publiczne, deklaracje prywatne. Deklaracje publiczne: mają miejsce w specyfikacji pakietu wynika to z faktu, iż swym zasięgiem obejmują one całą sesję bazodanową, a zatem wszystkie programy mające dostęp do tego pakietu mogą się do nich odwoływać. Deklaracje prywatne: są pewnymi deklaracjami oraz pewnymi dodatkowymi procedurami i funkcjami zdefiniowanymi w treści pakietu, są zatem dostępne jedynie treści pakietu, nie są dostępne z poziomu innych aplikacji języka PL/SQL. Zalety konstrukcji pakietów języka PL/SQL: to, iż pakiet składa się z dwóch odrębnych części jest następstwem ułatwień w organizacji i konserwacji kodu oraz ukrywania pewnych informacji, jest dość oczywistym fakt, iż w momencie, kiedy oddzielimy szczegóły implementacji od definicji, nie musimy kompilować powtórnie ani zmieniać podprogramów, kiedy zmienia się ich implementacja, natomiast w przypadku, gdy ulega zmianie logika biznesowa procedury lub funkcji umieszczonej w pakiecie, zmiana ta może zostać wdrożona tylko na poziomie treści pakietu. A zatem odwoływanie się do podprogramów pozostaje nienaruszone, w ten sposób używanie pakietów jest bardziej bezpieczne niż pojedynczych elementów wchodzących w skład samego pakietu, ponieważ nagłówek pakietu nie ulega zmianie, natomiast fakt, iż niektóre informacje mogą zostać ukryte w momencie korzystania z pakietu, wynika z samej struktury pakietu otóż w ramach pakietu występują deklaracje prywatne, co powoduje, iż elementy, których one dotyczą są specyficzne tylko dla tego pakietu i są niewidoczne poza tym pakietem dla innych użytkowników. Różnice pakietów w stosunku do innych bloków nazwanych (podprogramów): w odróżnieniu od procedur i funkcji, które mogą albo znajdować się w bloku, albo być składowane w bazie danych, pakiety mogą być tylko składowane nigdy też nie mają zasięgu lokalnego, poza umożliwieniem wspólnego grupowania obiektów skojarzonych, użyteczność pakietów polega na ograniczeniu znaczenia faktu istnienia zależności pomiędzy obiektami, pakiety dają również pewne korzyści związane z wydajnością pracy aplikacji. 2

Tworzenie pakietów Do tworzenia pakietów służą dwa polecenia: CREATE PACKAGE dla specyfikacji pakietu CREATE PACKAGE BODY dla jego treści. Wykonanie obu poleceń wymaga od użytkownika uprawnienia systemowego CREATE PROCEDURE. Aby utworzyć pakiet w innym schemacie, trzeba posiadać uprawnienie systemowe CREATE ANY PROCEDURE. Specyfikacja pakietu Specyfikacja pakietu (ang. specification) (znana również jako nagłówek pakietu): zawiera informacje dotyczące zawartości pakietu, mówiąc inaczej, zawiera jedynie informacje o jego przeznaczeniu, ale nie ma tu żadnych wiadomości o sposobie jego wykonania, zawiera jedynie nagłówki podprogramów, a nie ich treści., jest to zatem pewien rodzaj sekcji deklaracyjnej, który występuje w programach języka PL/SQL. Składnia nagłówka pakietu jest następująca: CREATE [OR REPLACE] PACKAGE nazwa_pakietu {IS AS} definicja typu deklaracja stałej deklaracja zmiennej deklaracja wyjatku deklaracja kursora specyfikacja procedury specyfikacja funkcji END [nazwa_pakietu] gdzie: nazwa_pakietu jest nazwą pakietu, poszczególne definicje odpowiadają definicjom typów, stałych, zmiennych, wyjątków, kursorów, nagłówków procedur i funkcji. Poniżej został przedstawiony przykład niezbyt skomplikowanego nagłówka pakietu: CREATE OR REPLACE PACKAGE PakietPracowniczy AS -- Przydzielenie pracownika do odpowiedniej grupy wynagrodzeń. PROCEDURE DodajPracownika (p_pracownikid p_grupa IN grupy.grupa%type, p_stawkagodz IN grupy.stawka%type); -- Usunięcie pracownika z danej grupy wynagrodzeń. PROCEDURE UsunPracownika (p_pracownikid p_grupa IN grupy.grupa%type, p_stawkagodz IN grupy.stawka%type); -- Wyjątek zgłoszony przez procedurę UsunPracownika w_pracownikniewprowadzony EXCEPTION; 3

FUNCTION WynagrPracownika (p_prac p_premia p_liczbagodz END PakietPracowniczy; IN NUMBER, IN NUMBER) RETURN NUMBER; Pakiet PakietPracowniczy zawiera dwie procedury, jedną funkcję oraz wyjątek. Poniżej zostały wymienione zasady, które są specyficzne dla nagłówka pakietu: W specyfikacji nagłówka pakietu mają miejsce deklaracje takich samych elementów języka PL/SQL (np. zmiennych, specyfikacji procedur i funkcji, itd.), jakie mogłyby się znaleźć w sekcji deklaracji bloku anonimowego. Deklaracja tych elementów jest w zasadzie analogiczna do ich możliwych deklaracji w bloku anonimowym, z wyjątkiem deklaracji procedury i funkcji (patrz poniżej). Instrukcja definicji specyfikacji pakietu rozpoczyna się od wyrażenia CREATE OR REPLACE, natomiast poszczególne podprogramy w nagłówku mają postać: PROCEDURE nazwa_procedury lub FUNCTION nazwa_funkcji A zatem w deklaracji podprogramów nie występują wyrażenia CREATE OR REPLACE. Wynika to stąd, iż w przypadku języka PL/SQL cały kod pojedynczego pakietu jest tworzony, uaktualniany lub usuwany jednocześnie, dlatego sensowne jest zastosowanie jednej instrukcji CREATE. Elementy pakietu mogą pojawiać się w dowolnej kolejności (także w przykładzie przytoczonym powyżej). Jednak w sekcji deklaracji obiekt musi zostać zadeklarowany, zanim nastąpi do niego odwołanie. Jeżeli kursor zawiera zmienną, np. w części klauzuli WHERE, zmienna musi być zadeklarowana przed deklaracją kursora. Występowanie wszystkich typów elementów nie jest obowiązkowe. Pakiet może zawierać tylko specyfikacje procedury i funkcji, np. bez deklarowania wyjątków lub typów. Każda deklaracja dla procedury lub funkcji musi być deklaracją wyprzedzającą. Deklaracja wyprzedzająca po prostu opisuje podprogram oraz jego argumenty (jeżeli takie istnieją), ale nie zawiera kodu. Inaczej jest w sekcji deklaracji bloku, gdzie mogą się znajdować zarówno deklaracje wyprzedzające, jak i właściwy kod procedur i funkcji. Kod, który implementuje procedury i funkcje pakietu, znajduje się w treści pakietu. Istota stosowania pakietów wynika zatem z faktu korzystne jest niejednokrotnie ukrycie bardzo skomplikowanych rozwiązań programistycznych poprzez ich prostą prezentację w tym przypadku za pomocą pakietów. Treść pakietu Treść pakietu, zwana inaczej ciałem: jest oddzielnym obiektem słownika danych związanym z nagłówkiem pakietu, jego kompilacja się nie powiedzie, jeśli nagłówek pakietu nie zostanie wcześniej pomyślnie skompilowany, zawiera kod odpowiadający deklaracji wyprzedzającej podprogramu w nagłówku pakietu, może również zawierać dodatkowe deklaracje, które są globalne dla treści pakietu, ale niewidoczne dla specyfikacji. Innymi słowy, ciało pakietu jest tą lokalizacją, gdzie umieszcza się implementacje programów wymienionych w nagłówku danego pakietu. 4

CREATE OR REPLACE PACKAGE BODY PakietPracowniczy AS -- Przydzielenie pracownika do odpowiedniej grupy wynagrodzeń. PROCEDURE DodajPracownika (p_pracownikid p_grupa IN grupy.grupa%type, p_stawkagodz IN grupy.stawka%type) AS INSERT INTO grupy_pracownikow (pracownik_id, grupa, stawka) VALUES(p_PracownikId, p_grupa, p_stawkagodz); END DodajPracownika; -- Usunięcie pracownika z danej grupy wynagrodzeń. PROCEDURE UsunPracownika (p_pracownikid p_grupa IN grupy.grupa%type, p_stawkagodz IN grupy.stawka%type) AS DELETE FROM grupy_pracownikow WHERE pracownik_id = p_pracownikid AND grupa = p_grupa; /* Sprawdzenie, czy operacja DELETE powiodła się. Jeśli nie znaleziono wierszy do usunięcia zgłoszenie błędu */ IF SQL%NOTFOUND THEN RAISE w_pracownikniewprowadzony; END IF; END UsunPracownika; -- Poniższa funkcja zwraca wynagrodzenie pracownika FUNCTION WynagrPracownika (p_prac p_premia IN NUMBER, p_liczbagodz IN NUMBER) RETURN p_wynagrodzenie NUMBER IS z_stawka zatrudnienie.stawka%type; CURSOR k_stawka IS SELECT stawka INTO z_stawka FROM zatrudnienie WHERE id = p_prac; p_wynagrodzenie:= p_liczbagodz*z_stawka*(1 + p_premia); END WynagrPracownika; END PakietPracowniczy; Analizując choćby powyższą treść przykładowego pakietu PakietPracowniczy należy zwrócić uwagę na następujące cechy charakterystyczne dla ciał pakietów: wymaganym jest, aby nagłówek i treść pakietu miały taką samą nazwę. na początku pakietu nie występuje słowo. Należy odróżnić ten fakt od tego, iż sekcja + sekwencja instrukcji występuje na końcu pakietu. Jest to sekcja inicjalizacyjna i dla pakietu nie ma charakteru. 5

podczas deklarowania stałych, zmiennych, definiowania typów, wyjątków i/lub kursorów nie jest używane słowo kluczowe DECLARE. podczas deklarowania procedur i/lub funkcji nie jest używana klauzula CREATE OR REPLACE. deklaracje publiczne mogą występować w dowolnej kolejności, o ile zadeklarujemy je przed odwołaniem się do nich. A zatem treść pakietu zawiera kod dla deklaracji wyprzedzających umieszczonych w nagłówku pakietu. Może również zawierać dodatkowe zmienne, kursory, typy lub podprogramy. Do tych obiektów w nagłówku, które nie są deklaracjami wyprzedzającymi (np. wyjątek w_pracownikniewprowadzony), w treści pakietu można odwoływać się bez ponownego deklarowania. w przypadku kursorów, specyfikacja może zawierać jedynie nazwę kursora oraz jego typ zwrotny. W takim przypadku kursor trzeba całkowicie zdefiniować w treści pakietu. Jeśli nie zadeklarujemy przy nim typu zwrotnego, wtedy cały kursor, a także skojarzoną z nim instrukcję SELECT, należy zadeklarować w specyfikacji pakietu, i nie ma potrzeby powtarzać tej deklaracji w treści pakietu. treści podprogramów (procedur i funkcji) należy powtórzyć w treści pakietu, podając stosowne szczegóły ich implementacji. Należy przestrzegać następującej zasady: każdej z publicznych procedur i/lub funkcji zdefiniowanych w nagłówku pakietu, musi odpowiadać jej implementacja w ciele pakietu. Ponadto sygnatura każdej procedury lub funkcji w nagłówku powinna odpowiadać słowo w słowo sygnaturze w treści pakietu. Treść pakietu jest elementem opcjonalnym. Jeżeli nagłówek pakietu nie zawiera żadnych procedur lub funkcji (a jedynie deklaracje zmiennych, kursory, typy, itd.), to nie trzeba definiować treści. Taka technika przydaje się podczas deklarowania globalnych zmiennych i typów, ponieważ wszystkie obiekty znajdujące się w pakiecie są widoczne na zewnątrz pakietu. Jak wynika z powyżej przytoczonych własności specyfikacji pakietów, każda deklaracja wyprzedzająca występująca w nagłówku pakietu musi mieć swoje rozwinięcie w treści pakietu. Specyfikacja procedury lub funkcji musi być taka sama w obu przypadkach. Dotyczy to nazwy podprogramu, nazwy jego parametrów oraz ich trybu. Poniższy, przykładowy nagłówek pakietu nie odpowiada zawartości pakietu, ponieważ dla funkcji FunkcjaA w zawartości pakietu występuje inna lista parametrów: CREATE OR REPLACE PACKAGE PakietA IS FUNCTION FunkcjaA(p_Parametr1 IN NUMBER, p_parametr2 IN DATE) RETURN VARCHAR2; END PakietA; CREATE OR REPLACE PACKAGE BODY PakietA AS FUNCTION FunkcjaA(p_Parametr1 IN CHAR) RETURN VARCHAR2 IS; END PakietA; Podczas próby utworzenia pakietu PakietA wystąpią następujące błędy: PLS-00328: Należy zdefiniować treść dla deklaracji wyprzedzającej FUNCTIONA. PLS-00323: podprogram lub kursor FUNCTIONA jest zadeklarowany w specyfikacji pakietu i musi być zdefiniowany w treści pakietu. 6

Odwoływanie się do obiektów pakietu Obiekty publiczne Poszczególne obiekty, które są zdefiniowane w nagłówku pakietu, mają zasięg globalny w takim sensie, iż są dostępne dla całej sesji i dla wszystkich aplikacji, które dysponują wymaganymi uprawnieniami. Dlatego też noszą nazwę obiektów publicznych. Każdy obiekt zadeklarowany w nagłówku pakietu znajduje się w zakresie jest widoczny na zewnątrz pakietu poprzez podanie nazwy obiektu z nazwą pakietu. Przykładowo, za pomocą poniższego bloku PL/SQL można wywołać procedurę P1 z pakietu o nazwie Nazwa_Pakiet: DECLARE tekst1 VARCHAR2(100); Nazwa_Pakiet.Procedura_P1( 1234, IX, 1890, tekst1); IF tekst1<>0 THEN DBMS_OUTPUT.PUT_LINE(tekst1); END IF; END; Wywołanie procedury jest analogiczne do samodzielnej procedury, a jedyną różnicą jest to, że nazwę procedury poprzedza nazwa pakietu. Po wykonaniu procedury sterowanie przechodzi do wywołującego bloku PL/SQL, tak jak to ma miejsce w przypadku samodzielnej procedury. Procedury pakietowe mogą przyjmować wartości domyślne i być wywołane z zastosowaniem notacji pozycyjnej albo imiennej, podobnie jak dla składowanych, samodzielnych procedur. Do obiektów, które znajdują się w nagłówku, w treści pakietu można odwoływać się bez podawania nazwy pakietu. Przykładowo, procedura UsunPracownika może wywołać wyjątek za pomocą samej jego nazwy w_pracownikniewprowadzony zamiast nazwy kwalifikowanej UsunPracownika.w_PracownikNiewprowadzony. Oczywiście, taką nazwę także można stosować. Wskazówka: Jednym ze sposobów, który pozwala spełnić warunek, iż każdej z publicznych procedur i funkcji zdefiniowanych w nagłówku pakietu, musi odpowiadać jej implementacja w ciele pakietu, polega na tym, iż podprogramy w ciele pakietu należy umieszczać w tej samej kolejności, jak w przypadku specyfikacji pakietu (podprogramy prywatne uwzględnia się na początku, gdyż ze względu na wymagania kompilatora ich definicja musi znajdować się przed ewentualnym wywołaniem). W razie niezdefiniowania któregoś z podprogramów, które uprzednio zostały wymienione w specyfikacji, kompilator nie przeprowadzi kompilacji, dopóki ten błąd nie zostanie naprawiony. Zakres obiektów w treści pakietu W analizowanej postaci pakietu, procedury PakietPracowniczy.DodajPracownika oraz PakietPracowniczy.UsunPracownika po prostu uaktualniają tabelę grupy_pracownicy. Takie działanie nie jest jednak wystarczające. Procedury te powinny jeszcze uaktualniać tabelę pracownicy, w celu uwzględnienia w niej tych pracowników, którzy są wprowadzeni po raz pierwszy oraz tych, którzy zostali z niej usunięci. W tym celu w treści pakietu można dodać nową procedurę, co ilustruje poniższy przykład: CREATE OR REPLACE PACKAGE BODY PakietPracowniczy AS 7

/* Procedura narzędziowa uaktualniająca tabele pracownicy i grupy_pracownicy w celu uwzględnienia zmian. Jeżeli parametr p_dodano ma wartość TRUE, to tabele są uaktualniane w związku z dodaniem nowego pracownika do grupy uposażenia. Jeżeli ma wartość FALSE, to są uaktualniane w celu uwzględnienia usunięcia pracownika PROCEDURE UaktualnijTabPracownicy(p_Dodano IN BOOLEAN, p_id p_nazwisko IN pracownicy.nazwisko%type, p_imie IN pracownicy.imie%type, p_plec IN pracownicy.plec%type) AS IF p_dodano THEN INSERT INTO pracownicy VALUES(p_id, p_nazwisko, p_imie, p_plec); ELSE DELETE FROM pracownicy WHERE id = p_id; END IF; END UAKTUALNIJTabPracownicy; PROCEDURE DodajPracownika (p_pracownikid p_grupa IN grupy.grupa%type, p_stawkagodz IN grupy.stawka%type) AS INSERT INTO grupy_pracownikow (pracownik_id, grupa, stawka) VALUES(p_PracownikId, p_grupa, p_stawkagodz); END DodajPracownika; -- Usunięcie pracownika z danej grupy wynagrodzeń. PROCEDURE UsunPracownika (p_pracownikid p_grupa p_stawkagodz DELETE FROM grupy_pracownikow WHERE pracownik_id = p_pracownikid AND grupa = p_grupa; IN grupy.grupa%type, IN grupy.stawka%type) AS /* Sprawdzenie, czy operacja DELETE powiodła się. Jeśli nie znaleziono wierszy do usunięcia zgłoszenie błędu */ IF SQL%NOTFOUND THEN RAISE w_pracownikniewprowadzony; END IF; END UsunPracownika; FUNCTION WynagrPracownika (p_prac p_premia p_liczbagodz z_stawka zatrudnienie.stawka%type; IN NUMBER, IN NUMBER) RETURN NUMBER IS 8

CURSOR k_stawka IS SELECT stawka INTO z_stawka FROM zatrudnienie WHERE id = p_prac; p_wynagrodzenie:= p_liczbagodz*z_stawka*(1 + p_premia); END WynagrPracownika; END PakietPracowniczy; 9

Przeciążanie podprogramów pakietowych Pojęcie przeciążania zostało wprowadzone wraz z pojawieniem się koncepcji programowania zorientowanego obiektowo (Object-OrientedProgramming, OOP). Programowanie zorientowane obiektowo pozwala na postrzeganie wszystkich elementów związanych z programem jako pewnej całości, zwanej obiektem. Obiekty mogą zawierać tabele, programy i metody przetwarzania danych. Integracja tych elementów umożliwia stosowanie modułowej konstrukcji środowiska programowania. Znane przykłady języków opartych na modelu programowania zorientowanego obiektowo to Java i C++. Możliwość przeciążania pozwala na tworzenie wielu wersji tego samego podprogramu. To, która z nich będzie uruchamiana, zależy od argumentów przesłanych do tego podprogramu (funkcji). Istnieje możliwość przeciążania procedur i funkcji wewnątrz pakietu. Jak z powyższego określenia tej własności wynika, proces przeciążania (ang. overloading) oznacza, iż w pakiecie występuje więcej niż jedna procedura lub funkcja o tej samej nazwie, ale z różnymi parametrami. Jest to bardzo użyteczna cecha, ponieważ w ten sposób ta sama operacja może dotyczyć obiektów różnych typów. Na potrzeby poniższego przykładu przyjęto, że istnieje potrzeba dodania produktu wycofanego określonej kategorii i dostarczanego przez określonego dostawcę poprzez określenie numeru produktu albo poprzez określenie jego nazwy, co jest możliwe poprzez modyfikacje pakietu PakietProduktu. CREATE OR REPLACE PACKAGE PakietProduktu AS /* Dodanie nowego produktu o określonej kategorii i dostarczanego przez określonego dostawcę poprzez podanie numeru produktu */ PROCEDURE DodajProdukt ( p_nr_produkt IN produkty.nr_prod%type, p_kod_dostawca IN produkty.kod_dost%type, p_nazwa_kategoria IN produkty.nazwa_kat%type); /* Dodanie nowego produktu o określonej kategorii i dostarczanego przez określonego dostawcę poprzez podanie nazwy produktu */ PROCEDURE DodajProdukt (p_nazwa_produkt p_kod_dostawca p_nazwa_kategoria IN produkty.nazwa_prod%type, IN produkty.kod_dost%type, IN produkty.nazwa_kat%type);... END PakiektProdukt; CREATE OR REPLACE PACKAGE BODY PakietProdukt AS /* Dodanie nowego produktu o określonej kategorii i dostarczanego przez określonego dostawcę poprzez podanie numeru produktu */ PROCEDURE DodajProdukt (p_nr_produkt p_kod_dostawca p_nazwa_kategoria IN produkty.nr_prod%type, IN produkty.kod_dost%type, IN produkty.nazwa_kat%type) AS 10

INSERT INTO produkty_wycofane(nr_prod, kod_dost, nazwa_kat) VALUES(p_Nr_produkt, p_kod_dostawca, p_nazwa_kategoria); COMMIT; END DodajProdukt; /* Dodanie nowego produktu o określonej kategorii i dostarczanego przez określonego dostawcę poprzez podanie nazwy produktu */ PROCEDURE DodajProdukt (p_nazwa_produkt IN produkty.nazwa_prod%type, p_kod_dostawca IN produkty.kod_dost%type, p_nazwa_kategoria IN produkty.nazwa_kat%type) AS z_nrprodukt produkty.nr_prod%type; /* Najpierw jest konieczne uzyskanie numeru produktu z tabeli produkty */ SELECT nr_prod INTO z_nrprodukt FROM produkty WHERE nazwa_prod = p_nazwa_produkt; /* Teraz można dodać produkt poprzez podanie numeru produktu */ INSERT INTO produkty_wycofane(nr_prod, kod_dost, nazwa_kat) VALUES(p_Nr_produkt, p_kod_dostawca, p_nazwa_kategoria); COMMIT; END DodajProdukt; END PakiektProdukt; Został utworzony pakiet, który zawiera dwie procedury o tych samych nazwach, lecz różnych parametrach. Teraz w celu dodania produktu wycofanego z kategorii nabiał dostarczanego przez dostawcę o numerze M0345 można zastosować kod: PakietProdukt.DodajProdukt(12457, Nabiał, M0345); END; lub kod: PakietProdukt.DodajProdukt( Śmietana 18%, Nabiał, M0345); END; Innym sposób wywołania procedury zawartej w pakiecie polega na wywołaniu jej z uwzględnieniem nazwy pakietu. A zatem w celu dodania produktu wycofanego z kategorii nabiał dostarczanego przez dostawcę o numerze M0345 można zastosować kod: EXECUTE PakietProdukt.DodajProdukt(12457, Nabiał, M0345); lub też nazwą produktu jako parametrem podprogramu: 11

EXECUTE PakietProdukt.DodajProdukt( Śmietana 18%, Nabiał, M0345); Jak z powyższych przykładów wynika: aby wywołać procedurę z pakietu, nazwę podprogramu należy poprzedzić nazwą pakietu, po której należy umieścić kropkę oraz nazwę procedury, która ma zostać wykonana, przeciążenie procedury nastąpiło w efekcie wywołania jej w dwóch oddzielnych sytuacjach, w pierwszym przypadku, został przesłana wartość liczbowa, która określa numer produktu, zaś w drugim został przesłany ciąg znaków określający nazwę produktu, na podstawie którego podprogram użył odpowiedniej procedury zdefiniowanej w ramach podprogramu. Uwaga: Ponieważ pakiety są ładowane w całości do wewnętrznej pamięci systemu Oracle, to własność ta może powodować znaczne przyśpieszenie działania programu, szczególnie w przypadku, gdy pakiet jest często używany. Przeciążanie podprogramów może okazać się bardzo użyteczną techniką, ponieważ ta sama operacja może być wykonana dla argumentów różnych typów. Technika przeciążania podlega jednak pewnym ograniczeniom: Nie można przeciążać dwóch podprogramów, jeżeli ich parametry różnią się tylko nazwą lub trybem, jak w poniższym przykładzie: PROCEDURE PrzeciazMnie ( p_parametr IN NUMBER); PROCEDURE PrzeciazMnie ( p_parametr OUT NUMBER); Nie można przeciążać dwóch funkcji tylko na podstawie różnicy typów zwracanych przez nie wartości, np. poniższe dwie funkcje nie mogą być przeciążone: FUNCTION PrzeciazMnie RETURN DATE; FUNCTION PrzeciazMnie RETURN NUMBER; Parametry funkcji przeciążanych muszą różnić się rodzinami typów nie można stosować techniki przeciążania, jeśli typy parametrów należą do tej samej rodziny typów. Przykładowo, CHAR oraz VARCHAR2 należą do tej samej rodziny, zatem nie można przeciążyć poniższych procedur: PROCEDURE PrzeciazMnie ( p_parametr IN CHAR); PROCEDURE PrzeciazMnie ( p_parametr IN VARCHAR2); Kompilator PL/SQL w rzeczywistości pozwala na utworzenie pakietu, który zawiera podprogramy naruszające powyżej wymienione ograniczenia. Jednak mechanizm wykonywania programu nie będzie mógł zrealizować poszczególnych odwołań i zawsze wygeneruje błąd: PLS-307: too many declarations of subprogram match this call (temu wywołaniu odpowiada za dużo deklaracji podprogramu ) 12

Tworzenie instancji i inicjalizacja pakietu Podczas pierwszego wywołania podprogramu albo dowolnego odwołania do zmiennej lub typu wchodzącego w skład pakietu zachodzi proces nazwany instancjonowaniem lub tworzenia instancji pakietu. Oznacza to, iż pakiet zostaje wczytany z dysku do pamięci i pozostaje w niej na czas sesji. Następnie zostaje wykonywany skompilowany kod wywoływanego podprogramu. Na tym etapie następuje przydzielenie pamięci wszystkim zmiennym zdefiniowanym w pakiecie. Dla każdej sesji jest przydzielana oddzielna kopia zmiennych pakietowych. W ten sposób dwie sesje wykonujące podprogramy w tym samym pakiecie wykorzystują różne miejsca w pamięci. W wielu przypadkach jest konieczne, aby za pierwszym razem, podczas instancjonowania pakietu, był wykonywany kod inicjalizacji. Można to osiągnąć poprzez dodanie sekcji inicjalizacji w treści pakietu po wszystkich innych obiektach. W tym celu stosuje się polecenie o następującej składni: CREATE OR REPLACE BODY nazwa_pakietu {IS AS} kod_inicjalizacji; END {nazwa_pakietu}; gdzie nazwa_pakietu jest nazwą pakietu, a kod_inicjalizacji jest kodem, który ma być wykonany. W kolejnym przykładzie zmodyfikujemy poprzednio rozważany PakietPracowniczy uzupełniony o sekcję inicjalizacyjną umieścimy w niej instrukcję SQL, która rejestruje nazwę użytkownika oraz znacznik czasu dla momentu, kiedy komponent jest uruchamiany w sesji po raz pierwszy. Do zarejestrowania tych wartości w treści pakietu trzeba zadeklarować dwie zmienne, które nie będą dostępne publicznie (UserNazwa i UserData). Zostaną one oddzielone od procedur i funkcji. Oto treść pakietu z kodem inicjalizacyjnym: CREATE OR REPLACE PACKAGE BODY PakietPracowniczy AS /* Dwie zmienne wykorzystywane przy pierwszym uruchomieniu pakietu podczas tzw. inicjowania pakietu */ UserNazwa UserData VARCHAR2(30); DATE; -- Przydzielenie pracownika do odpowiedniej grupy wynagrodzeń. PROCEDURE DodajPracownika (p_pracownikid p_grupa IN grupy.grupa%type, p_stawkagodz IN grupy.stawka%type) AS INSERT INTO grupy_pracownikow (pracownik_id, grupa, stawka) VALUES(p_PracownikId, p_grupa, p_stawkagodz); END DodajPracownika; -- Usunięcie pracownika z danej grupy wynagrodzeń. PROCEDURE UsunPracownika (p_pracownikid p_grupa IN grupy.grupa%type, p_stawkagodz IN grupy.stawka%type) AS DELETE FROM grupy_pracownikow WHERE pracownik_id = p_pracownikid 13

AND grupa = p_grupa; /* Sprawdzenie, czy operacja DELETE powiodła się. Jeśli nie znaleziono wierszy do usunięcia zgłoszenie błędu */ IF SQL%NOTFOUND THEN RAISE w_pracownikniewprowadzony; END IF; END UsunPracownika; FUNCTION WynagrPracownika (p_prac p_premia IN NUMBER, p_liczbagodz IN NUMBER) RETURN NUMBER IS z_stawka zatrudnienie.stawka%type; CURSOR k_stawka IS SELECT stawka INTO z_stawka FROM zatrudnienie WHERE id = p_prac; p_wynagrodzenie:= p_liczbagodz*z_stawka*(1 + p_premia); END WynagrPracownika; SELECT USER, SYSDATE INTO UserNazwa, UserData FROM Dual; END PakietPracowniczy; / Jeśli chodzi o sposób inicjalizacji pakietu, to należy zauważyć, że kod, który ma być uruchomiony przy pierwszym wykonaniu komponentu pakietu: jest deklarowany jako ostatnia część treści pakietu, tj. w dolnej jego części, nie ma oddzielnej instrukcji END dla instrukcji inicjującej pakiet podczas sesji instancjonowania wykorzystuje klauzulę END treści pakietu. sekcja inicjalizacyjna jest wykonywana tylko raz, w czasie tworzenia instancji pakietu. Kiedy komponent pakietu PakietPracowniczy zostanie uruchomiony po raz pierwszy w sesji użytkownika, zapytanie (pogrubione na listingu kodu powyżej) ustawi zmienne UserNazwa i UserData. Można je następnie wykorzystać w funkcjach i procedurach wewnątrz pakietu, chociaż w celu zachowania zwięzłości w tym pakiecie ich nie wykorzystano. Korzyści wynikające z wykorzystywania pakietów Jak się okazuje, istnieje wiele powodów, dla których warto używać pakietów języka PL/SQL. Poniżej zostały wypunktowane najistotniejsze korzyści wynikające z wykorzystywania pakietów języka PL/SQL: organizacja kodu programu w ramach pakietu mamy możliwość zgrupowania odpowiednio ze sobą powiązanych jednostek programowych. Zabieg ten pozwala na tworzenie kodu zorganizowanego w wygodne do stosowania 14

struktury. Można powiedzieć, używając odpowiedniej terminologii, iż pakiety pozwalają na wykorzystywanie mechanizmów abstrakcji, enkapsulacji oraz ukrywania informacji. zarządzanie dużą liczbą elementów oprogramowania grupowanie różnego rodzaju jednostek programowych języka PL/SQL w znacznym stopniu ułatwia zarządzanie dużą liczbą jednocześnie wykorzystywanych elementów oprogramowania. Wynika to także z predyspozycji samego człowieka, który w danej chwili czasowej jest w stanie wykorzystywać ograniczoną liczbę jednostek programowych dowolnego języka programowania. wydajność ponieważ w momencie pierwszego uruchomienia programu w pakiecie system Oracle wczytuje do pamięci całą zawartość pakietu, a nie tylko sam wywoływany program, to takie działanie powoduje, iż zwiększa się wydajność w momencie wywoływania innych programów umieszczonych w pakiecie. Wynika to oczywiście ze zmniejszenia liczby operacji wejścia/wyjścia podczas wykorzystania innych elementów programowych umieszczonych w pakiecie. Ponadto jest to następstwem tego, iż nie ma potrzeby korzystania z danych umieszczonych na wolniejszym dysku twardym, bo zostały one już wczytane przez system. Jak z tego wynika, w pakiecie warto przechowywać tylko te komponenty programowe, które są ze sobą powiązane. usprawnienie pracy sesyjnej podczas trwania sesji występuje niekiedy konieczność przechowywania w pamięci pewnych tymczasowych lub stałych wartości. Dzięki wykorzystaniu pakietów tego typu wartości można przechowywać w globalnych lub lokalnych zmiennych. Bez zastosowania pakietów wartości tego typu musiałyby być przechowywane w samej bazie danych, co z kolei miałoby niekorzystny wpływ na wydajność systemu (powyżej cecha wydajność). Problematyczne też byłoby odwoływanie się do pewnej wartości po wycofaniu transakcji. usprawnienie procesu rekompilacji w przypadku dużych systemów składających się z bardzo dużej liczby (liczonej w setkach lub więcej) programów, dużym problemem może stać się proces rekompilacji części składowych programu po dokonaniu pewnych zmian. Dzięki pakietom można uniknąć wielu trudności dzięki temu, ze można rekompilować zawartość ciała pakietu, bez konieczności rekompilacji programów, które wykorzystuje zmodyfikowany program. W przypadku zmiany specyfikacji pakietu trzeba już jednak ponownie skompilować każdy program uwzględniony w pakiecie, ale często tę czynność system Oracle wykonuje automatycznie. możliwość wykorzystania szczególnych cech języka PL/SQL wykorzystując pakiety języka PL/SQL mamy możliwość wykorzystania pewnej interesującej i użytecznej cechy języka PL/SQL, jaką jest możliwość tworzenia wielu jednostek programowych o tej samej nazwie. Pozwala to np. na wywołanie jednego programu, który może obsługiwać dane wejściowe o różnych typach. Technika ta nosi nazwę przeciążania (ang. overloading) i jest niedostępna dla programów, które nie zostały umieszczone w pakiecie. W ten sposób przeciążanie przyczynia się do stworzenia programu, który jest w pewien sposób jakby bardziej uniwersalny. 15