Un pachet (package) este o bibliotecă de obiecte stocate pe server, de tipul procedurilor stocate, funcțiilor, cursoarelor, tipurilor de date, excepțiilor, variabilelor și constantelor. Toate obiectele declarate în secțiunea de creare a unui pachete sunt globale (publice) și pot fi apelate din orice program PL/SQL, asemănător variabilelor globale din alte limbaje de programare; Un pachet este compus din două secțiuni distincte:
Principalele avantaje oferite de un pachet sunt:
Specificațiile reprezintă partea publică a unui pachet și au următoarea sintaxă:
CREATE [OR REPLACE] PACKAGE package_name {IS|AS} global (public) types AND variable declarations global (public) subprogram specifications END [package_name]
Unde :
Subprogramele, variabilele și cursoarele care vor fi apelate din exterior trebuie să fie cuprinse în secțiunea de creare a pachetului, pe când subprogramele, cursoarele, excepțiile, constantele, variabilele și tipurile de date folosite doar în pachet vor fi declarate doar în secțiunea body a acestuia. Referirea într-un program PL/SQL a unei componente globale (publice) a unui pachet se face folosind numele componentei, având ca prefix numele pachetului:
package_name.type_name package_name.item_name package_name.subprogram_name
Unde:
Dacă compilarea unui pachet se face cu succes, apare mesajul: Package created. În caz că apar erori la crearea unui pachet apare mesajul de avertizare: Warning: Package created with compilation errors.
Corpul unui pachet (package body) conține descrierea efectivă a procedurilor și funcțiilor definite în specificații. Această parte poate să conțină și componente locale (private) care sunt folosite doar în interiorul pachetului.
Sintaxa este:
CREATE [OR REPLACE] PACKAGE BODY package_name IS|AS LOCAL TYPE AND variable declarations subprogram bodies [BEGIN initialization statements END;] END [package_name]
Unde:
Cursoarele, tipurile de date, excepțiile, variabilele și constantele declarate în corpul pachetului vor avea caracter local (privat), deci vor fi accesibile numai în blocurile în care au fost definite. La primul apel al unui obiect dintr-un pachet, întregul pachet este inițializat. Inițializarea implică încărcarea unui pachet de pe disc în memorie și alocarea de spațiu în memorie pentru variabilele globale (publice).
Dacă apelul se referă la o procedură sau funcție, inițializarea este urmată de execuția codului deja compilat. Fiecare sesiune de lucru are o copie proprie a variabilelor din pachet. Sesiuni diferite pot apela același pachet, dar fiecare apel al pachetului aițializări prin atribuiri directe sau apelează proceduri de inițializare.
Ex. 1 Să se scrie un pachet p_angajare, care conține o funcție și o procedură, pentru a face o listă cu angajații care au venit în firmă înaintea unui director al companiei(care le este șef direct) și au primit comision. Șeful direct al unui angajat este specificat în coloana mgr. Procedura va insera rezultatele în tabela lista.
Pasul I – crearea tabelei lista
Pasul II – crearea specificațiilor
Pasul III – crearea corpului pachetului
Pasul IV – execuția pachetului
Pasul V – rezultatul execuției
SELECT * FROM lista;
În pachete nu se permite declararea a două proceduri sau funcții cu același nume, dacă parametrii acestora diferă numai prin nume sau mod (IN, OUT, IN OUT). Trebuie ca cel puțin un parametru să fie de un alt tip, iar tipul nu trebuie să fie din aceeași familie(de exemplul tipul CHAR este din aceeași familie cu VARCHAR2). Aceeași situație este și în cazul rezultatelor returnat de o funcție.
Exemplu de ambiguitate:
Exemplul se compilează fără erori, însă dacă executăm blocul atunci o să apară o eroare:
O variabilă globală (publică) poate fi folosită pentru a inițializa un parametru al subprogramelor (public/privat) cât și în interiorul acestora. De exemplu construcția următoare este permisă:
O variabilă locală (privată) poate fi folosită pentru a inițializa un parametru al unei subprogram local (privat) și în interiorul subprogramelor (private/publice). De exemplu construcția următoare este permisă:
Deoarece pachetele sunt create ca oricare alt obiect, din dicționarul bazei de date putem să aflăm informații despre ele făcând interogări pe view- urile sistemului de gestiune ORACLE. De exemplu dacă vrem să vedem toate pachetele create de userul curent, data când au fost create, data ultimei modificări și starea lor, putem să executăm următoarea cerere SQL:
Pentru a vedea care pahete au specificații și nu au secțiunea body se execută următoarea cerere SQL:
Specificațiile și corpul unui pachet se pot șterge din dicționar folosind comanda DDL, DROP:
DROP PACKAGE pakage_name;
Pentru a șterge numai corpul unui pachet se folosește comanda SQL:
DROP PACKAGE BODY package_name;
Pentru a da privilegii de execuție a pachetelor altor utilizatori, utilizatorul care a creat pachetul (sau administratorul) poate folosi comanda DCL, GRANT:
GRANT EXECUTE ON package_name TO user_name;
Utilizatorul grantificat poate apela un obiect din pachetul respectiv, specificând în apel userul, pachetul și obiectul. De exemplu, o procedură fără parametri poate fi apelată direct din SQL*Plus astfel:
EXECUTE user_name.package_nane.procedure_name;
O procedură poate fi apelată și dintr-un bloc SQL:
DECLARE BEGIN ... user_name.package_name.procedure_name; ... END;
Pentru a revoca privilegiile de execuție se folosește comanda REVOKE:
REVOKE EXECUTE ON package_name FROM user_name;
Serverul Oracle conține câteva pachete standard(de sistem), care sunt instalate odată cu serverul de baze de date. Câteva din cele mai uzuale pachete standard sunt:
UTL_FILE – permite programatorilor PL/SQL să scrie și să citească fișiere text gestionate de sistemul de operare. Pentru aceasta, se poate folosi funcția fopen pentru deschiderea fișierului și procedura get_line pentru citirea linie cu linie;
Informațiile din dicționar, legate de pachetele standard, se obțin folosind view-urile de sistem DBA_OBJECTS și DBA_SOURCE, acesibile userului system sau celor care au privilegiul DBA.
Pentru vizualizarea mai multor informații din dicționar, legate de pachetele standard, se poate folosi cererea SQL:
SELECT text FROM dba_source WHERE LOWER(name) = 'package_name' AND LOWER(TYPE)='package' ORDER BY line;
SET standard_package {ON|OFF}
Ex. 2 Să se scrie un pachet care conține:
Procedura face o listă care are antetul: