
A példaprogram használata előtt létre kell hozni egy SOUSER sémát az Oracle adatbázis-rendszerünkben, és fel kell ruházni DBA jogosultsággal. A mellékelt program az ezt megelőző cikk adattábláira támaszkodik, így az Oracle04.sql script lefuttatása csak az említett táblák hiánya esetén szükséges. Ezek meglétéről meg kell győződni, ugyanis ezek hiányában a létrehozandó további objektumok létrejönnek ugyan, de fordítási hibával. A sémába bejelentkezve le kell viszont futtatni a mellékelt Oracle04ph.sql és Oracle04pb.sql script-eket a hivatkozott további objektumok létrehozásához.
Csomagok fejlesztése
A csomag olyan, magas szintű adatabsztrakciós eszköz, mellyel az összetartozó változókat, konstansokat és alprogramokat írhatjuk le, és kezelhetjük egy egységként. Felhasználója a csomagból pontosan annyit láthat egy előre definiált interfészen keresztül, amennyi a csomagban megvalósított funkciók végrehajtásához számára szükséges, de a konkrét megvalósítás részleteit a csomag felhasználója elől elrejti.
A PL/SQL csomagok a korábbi korábbiakban megismert objektumokat, nevezetesen konstansokat, változókat, tárolt eljárásokat és függvényeket, valamint a későbbiekben ismertetett kurzorokat, kivételes állapotokat tartalmazhatnak.
A csomagok két fő részből állnak:
A csomag nyilvános része. A csomag kívülről elérhető elemeit adja meg, melyeken keresztül a felhasználók a csomag objektumaira hivatkozhatnak. A csomag specifikáció típusdefiníciókat, konstans-, változó- és kurzor deklarációkat, valamint eljárás- és függvény definíciókat tartalmazhat, azonban blokkokat (tehát névtelen blokkot, illetve eljárás- vagy függvénytörzset) nem.
A csomag privát része, melynek elemei a felhasználók számára nem hozzáférhetők. A csomag specifikációban megadott eljárások és függvények teljes definícióit tartalmazza (fejléccel és törzzsel együtt). Ezen kívül tartalmazhat még típusdefiníciókat, konstans, változó és kurzor deklarációkat is.
A csomag fejlesztése alapvetően 3 lépésből áll:
- Készítsük el a csomag specifikációt, és helyezzük el egy szöveges állományban.
- Készítsük el a csomag törzsét, és helyezzük el egy másik szöveges állományban.
- Futtassuk a létrehozott szöveges állományokat az SQL*Plus segítségével. Ezzel a csomag fejét és törzsét tároltuk az adatbázisban, a forráskód P-kóddá alakul (a P-kódról bővebben az előző cikkben olvashat).
- A csomag bármely nyilvános elemére hivatkozhatunk a szintaktikai szabályoknak megfelelően.
A nyilvános építőelemeket a csomagok specifikációs részében deklaráljuk a CREATE PACKAGE utasítás segítségével, melynek szintaxisa a következő:
CREATE OR REPLACE PACKAGE <csomagnév> IS
{<típus definíció> | <kivétel definíció> | <konstans definíció> | <változó deklaráció> | <kurzor deklaráció> | <eljárás fej> | <függvény fej>}
END {<csomagnév>}
A nyilvános (csomag specifikációban deklarált) változók értékeire a csomagon kívülről is hivatkozhatunk, értékeik meg is változtathatók. A nyilvános eljárás vagy függvény a csomagon kívülről meghívható és végrehajtható.
A csomag specifikációban elhelyezett változók értéke közvetlenül olvasható és írható is, ez azonban a csomag strukturáltságát rontja, hiszen az alapelv az, hogy a csomagban elhelyezkedő adatokhoz csak a csomag procedúráin keresztül lehessen hozzáférni.
Ezért a legjobb módja a nyilvános változó deklarációjának a következő: hozzunk létre egy privát változót, és deklaráljunk olyan nyilvános alprogramokat, melyek a privát változó értékét változtatják, vagy adják vissza.
Lássunk ezzel kapcsolatban egy példát:
A példa EMP_PACK nevű csomagjában egy képzeletbeli, dolgozói adatokat tároló táblán (EMP) végezhetünk műveleteket anélkül, hogy ismernénk a tábla pontos felépítését. A függvénnyel felvehetünk egy dolgozót:
CREATE OR REPLACE PACKAGE EMP_PACK IS
v_hired DATE;
PROCEDURE hire_emp(p_empno IN NUMBER, p_name IN VARCHAR, p_sal IN NUMBER);
END EMP_PACK;
A csomag privát építőelemeinek helye tehát a csomagtörzs, melyet a következő szintaxissal hozhatunk létre:
CREATE OR REPLACE PACKAGE BODY <csomagnév> IS
{<típus definíció> | <kivétel definíció> | <konstans definíció> | <változó deklaráció> | <kurzor deklaráció> | <eljárás definíció> | <függvény definíció>}
END {<csomagnév>}
Mielőtt a csomag törzsében egy elemre hivatkoznánk, definiálnunk kell azt. Privát eljárások segítségével a nyilvános alprogramok törzsét modularizálhatjuk, ezzel áttekinthetőbbé tehetjük őket. A fenti példacsomag törzse:
CREATE OR REPLACE PACKAGE BODY EMP_PACK IS
PROCEDURE hire_emp(p_empno IN NUMBER, p_name IN VARCHAR, p_sal IN NUMBER)
IS
BEGIN
INSERT INTO EMP (empno, name, sal, hiredate) VALUES (p_empno, p_name, p_sal, v_hired);
COMMIT;
END hire_emp;
END EMP_PACK;
A változók kezdeti értékeinek ’bedrótozása’ helyett lehetőségünk van arra, hogy egy automatikusan végrehajtódó ’egylövetű’ (one-time-only) BEGIN-END blokkot készítsünk a csomagtörzsben. Egy adott munkameneten belül az egylövetű blokk végrehajtódik a csomag bármely elemének első meghívásakor. A fenti példához adjunk egy kiegészítést, mely a v_hired változó értékét állítja be az aktuális dátumra (feltételezve, hogy egyik munkamenet sem tart tovább egy napnál).
CREATE OR REPLACE PACKAGE BODY EMP_PACK IS
-- Eljárás törzsek;
BEGIN
V_hired := SYSDATE;
END EMP_PACK;
Csomagok tárolása, hivatkozás csomagok elemeire
Ahogy az alprogramokat, a csomagokat is az adatszótárba tárolja az Oracle. Létrehozásuk, törlésük és módosításuk is a megszokott módon történik:
| Parancs |
Művelet |
| CREATE [OR REPLACE] PACKAGE |
Létrehoz egy új csomag specifikációt, vagy módosít egy már meglévőt. |
| CREATE [OR REPLACE] PACKAGE BODY |
Létrehoz egy új csomagtörzset, vagy módosít egy már meglévőt. |
| DROP PACKAGE |
Törli egy csomag specifikációját és törzsét is. |
| DROP PACKAGE BODY |
Törli egy csomag törzsét. |
A csomag törzsének módosítása vagy törlése nem követeli meg a specifikáció megfelelő módosítását vagy törlését.
A miután a csomagot tároltuk az adatbázisban, annak egyes elemeire a csomagon belülről vagy kívülről is hivatkozatunk annak megfelelően, hogy az elem privát vagy nyilvános. Ha csomag elemére belülről hivatkozunk, nem kell kitenni az elem neve elé a csomag nevét. Kívülről való hivatkozáskor azonban meg kell adnunk a csomag nevét az elem neve előtt egy ponttal elválasztva. Az említett EMP_PACK csomag hire_emp nevű tárolt eljárására a következőképpen hivatkozhatunk:
EXECUTE EMP_PACK.HIRE_EMP(1001,...);
A csomagok használatának számos előnye van, amelyeket most összefoglalunk:
- Javítják a tárolt alprogramok strukturáltságát: az összetartozó eljárásokat és függvényeket egy egységként kezelhetjük és feloldhatjuk az egy sémán belüli névkonfliktusokat.
- A tárolt alprogramok kezelése egyszerűsödik: korlátozza a procedurális függéseket; a csomagok törzsét a specifikációtól függetlenül módosíthatjuk.
- Javul a tárolt alprogramok használatának biztonsága: elrejti a forráskódot a felhasználók elől; a teljes csomagra érvényes hozzáférési jogokat csak egyszer kell megadni.
- A változókra globálisan hivatkozhatunk bármely környezetből.
- Javítja a teljesítményt: az első hivatkozáskor a teljes csomag a memóriába töltődik és lefordul, így csökken a lemezműveletek száma.
Az Oracle rendelkezik bizonyos előre gyártott csomagokkal, melyek funkciói elérhetők. A beépített csomagok közül egyet emelnénk ki, mely nagy segítséget jelenthet a tárolt alprogramok adatainak megjelenítésében, valamint a fordítási hibák felderítésében. A csomag neve DBMS_OUTPUT, melynek köszönhetően a tárolt alprogramok kimenő értékeit és üzeneteket jeleníthetünk meg. Ilyen módon adatokat gyűjthetünk egy pufferbe, ahol ezeket majd elérhetjük.
A DBMS_OUTPUT csomag elemei:
| Elem neve |
Művelet |
| PUT |
Szöveget fűz a kimeneti puffer aktuális sorához. |
| NEW_LINE |
Sor vége jelet tesz a kimeneti pufferbe. |
| PUT_LINE |
Az előbbi kettő kombinációja. |
| GET_LINE |
Visszaadja a kimeneti puffer aktuális sorát. |
| GET_LINES |
Visszaadja a kimeneti puffer összes sorát. |
| ENABLE |
Engedélyezi a DBMS_OUTPUT alprogramjainak hívását. |
| DISABLE |
Letiltja a DBMS_OUTPUT alprogramjainak hívását. |
Bizonyosodjunk meg róla, hogy a DMBS_OUTPUT csomag elérhető. Ehhez le kell futtatni a SYS sémában a dbmsotpt.sql parancsállományt, melyet a catproc.sql hív meg a procedurális opció installálásának részeként. A DBMS_OUTPUT puffer engedélyezésre és tiltására a SQL*Plus a SET SERVEROUTPUT ON/OFF parancsokat tartalmazza.
A mellékelt alkalmazásban egy csomagot használunk, melynek ’WriteString’ nevű eljárása illusztrálja, milyen módon írhatunk tárolt alprogramból a pufferbe. Az eljárás egy VARCHAR bemenő paramétert kap, melyet kiír a hívó környezetbe a DBMS_OUTPUT csomag PUT_LINE eljárása segítségével. A puffer engedélyezése után hívás a következő:
SET SERVEROUTPUT ON;
EXECUTE Collection.WriteString(’A kiírandó szöveg...’);
A mellékelt programban az Oracle04ph.sql és az Oracle04pb.sql parancsállományok segítségével hozható létre a ’Collection’ nevű csomag specifikációja és törzse. A tartalmazott eljárások nevei: ’GetSumPrice’ és ’WriteString’. Az előbbi eljárás műveletében megegyezik az ezt megelőző cikkben leírtakkal, vagyis megadja egy dolgozó neve alapján annak értékesítéseinek összegét. A Form elemei segítségével ez elvégezhető. Itt most a hangsúly a csomag elemeinek felhasználásán volt, vagyis hogy eljárásainkat egy csomag részeiként érjük el. Ennek érdekében a proc OleDbCommand komponens CommandText property-jében az eljárás minősített nevét kellett megadni:
proc.CommandText = "Collection.GetSumPrice";
A mellékelt programban a fő Form alsó táblázatában tekinthető meg a TRIPS tábla adathalmaza, míg a DEALERS tábla értékeit a „DEALERS tábla” feliratú gombra kattintva megjelenő Form-on nézhetjük meg. Ezekből követhetjük az eredmény helyességét.
A Form-on elhelyezett TabControl kontrol megfelelő fülét választva, majd a dolgozó nevét megadva a ComboBox kontrolban kapható meg az eredmény az „Összesítés” gomb megnyomásával.