Sunteți pe pagina 1din 19

Subprograme n PL/SQL

Noiunea de subprogram (procedur sau funcie) a fost conceput cu scopul de a grupa o mulime de comenzi SQL cu instruciuni procedurale pentru a construi o unitate logic de tratament. Unitile de program ce pot fi create n PL/SQL sunt: subprograme locale (definite n partea declarativ a unui bloc PL/SQL sau a unui alt subprogram); subprograme independente (stocate n baza de date i considerate drept obiecte ale acesteia); subprograme mpachetate (definite ntr-un pachet care ncapsuleaz proceduri i funcii). Procedurile i funciile stocate sunt uniti de program PL/SQL apelabile, care exist ca obiecte n schema bazei de date Oracle. Recuperarea unui subprogram (n cazul unei corecii) nu cere recuperarea ntregii aplica ii. Subprogramul ncrcat n memorie pentru a fi executat, poate fi partajat ntre obiectele (aplicaii) care l solicit. Este important de fcut distincie ntre procedurile stocate i procedurile locale (declarate i folosite n blocuri anonime). Procedurile care sunt declarate i apelate n blocuri anonime sunt temporare. O procedur stocat (creat cu CREATE PROCEDURE sau coninut ntr-un pachet) este permanent n sensul c ea poate fi invocat printr-un script iSQL*Plus, un subprogram PL/SQL sau un declanator. Procedurile i funciile stocate, care sunt compilate i stocate n baza de date, nu mai trebuie s fie compilate a doua oar pentru a fi executate, n timp ce procedurile locale sunt compilate de fiecare dat cnd este executat blocul care conine procedurile i funciile respective. Procedurile i funciile stocate pot fi apelate din orice bloc de ctre utilizatorul care are privilegiul EXECUTE asupra subprogramului, n timp ce procedurile i funciile locale pot fi apelate numai din bloc ul care le conine. Cnd este creat un subprogram stocat, utiliznd comanda CREATE OR REPLACE, subprogramul este depus n dicionarul datelor. Este depus att textul surs, ct i forma compilat (p-code). Cnd subprogramul este apelat, p-code

este citit de pe disc, este depus n shared pool, unde poate fi accesat de mai muli utilizatori i este executat dac este necesar. El va prsi shared pool conform algoritmului LRU (least recently used). Subprogramele se pot declara n blocuri PL/SQL, n alte subprograme sau n pachete, dar la sfritul seciunii declarative. La fel ca blocurile PL/SQL anonime, subprogramele conin o parte declarativ, o parte executabil i opional, o parte de tratare a erorilor.

Crearea subprogramelor stocate


1) se editeaz subprogramul (CREATE PROCEDURE sau CREATE FUNCTION) i se salveaz ntr-un script file SQL; 2) se ncarc i se execut acest script file, este compilat codul surs, se obine p-code (subprogramul este creat); 3) se utilizeaz comanda SHOW ERRORS (n iSQL*Plus sau in SQL*Plus) pentru vizualizarea eventualelor erori la compilare ale procedurii care a fost cel mai recent compilata sau SHOW ERRORS PROCEDURE nume pentru orice procedura compilata anterior (nu poate fi invocata o procedura care contine erori de compilare); 4) se execut subprogramul pentru a realiza aciunea dorit (de exemplu, procedura poate fi executat de cte ori este necesar, utiliznd comanda EXECUTE din iSQL*Plus) sau se invoc funcia dintr-un bloc PL/SQL. Cnd este apelat subprogramul, motorul PL/SQL execut p-code. Dac exist erori la compilare i se fac coreciile corespunztoare, atunci este necesar fie comanda DROP PROCEDURE (respectiv DROP FUNCTION), fie sintaxa OR REPLACE n cadrul comenzii CREATE. Cnd este apelat o procedur PL/SQL, server-ul Oracle parcurge etapele: 1) Verific dac utilizatorul are privilegiul s execute procedura (fie pentru c el a creat procedura, fie pentru c i s -a dat acest privilegiu). 2) Verific dac procedura este prezent n shared pool. Dac este prezent va fi executat, altfel va fi ncrcat de pe disc n database buffer cache. 3) Verific dac starea procedurii este valid sau invalid. Starea unei proceduri PL/SQL este invalid, fie pentru c au fost detectate erori la compilarea procedurii, fie pentru c structura unui obiect s-a schimbat de cnd procedura a fost executat ultima oar. Dac starea procedurii este invalid atunci este recompilat automat. Dac nici o eroare nu a fost

detectat, atunci va fi executat noua versiune a procedurii. 4) Dac procedura aparine unui pachet atunci toate procedurile i funciile pachetului sunt de asemenea ncrcate n database cache (dac ele nu erau deja acolo). Dac pachetul este activat pentru prima oar ntr-o sesiune, atunci server-ul va executa blocul de iniializare al pachetului. Pentru a afia codul unui subprogram, parametrii acestuia, precum i alte informaii legate de subprogram poate fi utilizat comanda DESCRIBE.

Proceduri PL/SQL
Procedura PL/SQL este un program independent care se gsete compilat n schema bazei de date Oracle. Cnd procedura este compilat, identificatorul acesteia (stabilit prin comanda CREATE PROCEDURE) devine un nume obiect n dicionarul datelor. Tipul obiectului este PROCEDURE. Sintaxa general pentru crearea unei proceduri este urmtoarea: [CREATE [OR REPLACE]] PROCEDURE nume_procedur [(parametru[, parametru]...)] {IS | AS} [declaraii locale] BEGIN partea executabil [EXCEPTION partea de mnuire a excepiilor] END [nume_procedur]; unde parametrii au urmtoarea form sintactic: nume_parametru [IN | OUT [NOCOPY] | IN OUT [NOCOPY] tip_de_date{:= | DEFAULT} expresie]

Clauza CREATE permite ca procedura s fie stocat n baza de date. Cnd procedurile sunt create folosind clauza CREATE OR REPLACE, ele vor fi stocate n BD n form compilat. Dac procedura exist, atunci clauza OR REPLACE va avea ca efect tergerea procedurii i nlocuirea acesteia cu noua versiune. Dac procedura exist, iar OR REPLACE nu este prezent, atunci comanda CREATE va returna eroarea ORA-955: Name is already used by an existing object. Parametrii formali (variabile declarate n lista parametrilor specificaiei subprogramului) pot s fie de tipul: %TYPE, %ROWTYPE sau un tip explicit fr specificarea dimensiunii.

Exemplu: S se creeze o procedur stocat care micoreaz cu o cantitate dat ( cant) valoarea polielor de asigurare emise de firma ASIROM. CREATE OR REPLACE PROCEDURE mic (cant IN NUMBER) AS BEGIN UPDATE politaasig SET valoare = valoare - cant WHERE firma = 'ASIROM'; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20010,nu exista ASIROM); END; CREATE OR REPLACE PROCEDURE mic (cant IN NUMBER) AS BEGIN UPDATE employees SET salary = salary - cant; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20010,nu exista ASIROM); END; /

Exemplu: S se creeze o procedur local prin care se insereaz informaii n tabelul editata_de. DECLARE PROCEDURE editare (v_cod_sursa editata_de.cod_sursa%TYPE, v_cod_autor editata_de.cod_autor%TYPE) IS BEGIN INSERT INTO editata_de VALUES (v_cod_sursa,v_cod_autor); END; BEGIN editare(75643, 13579); END;

Procedurile stocate pot fi apelate: din corpul altei proceduri sau a unui declanator; interactiv de utilizator utiliznd un instrument Oracle (de exemplu, iSQL*Plus); explicit dintr-o aplicaie (de exemplu, SQL*Forms sau utilizarea de precompilatoare). Utilizarea (apelarea) unei proceduri se poate face: 1) n iSQL*Plus prin comanda: EXECUTE nume_procedur [(lista_parametri_actuali)];
2) n PL/SQL prin apariia numelui procedurii urmat de lista parametrilor

actuali.

Funcii PL/SQL
Funcia PL/SQL este similar unei proceduri cu excepia c ea trebuie s ntoarc un rezultat. O funcie fr comanda RETURN va genera eroare la compilare. Cnd funcia este compilat, identificatorul acesteia devine obiect n dicionarul datelor avnd tipul FUNCTION. Algoritmul din interiorul corpului subprogramului funcie trebuie s asigure c toate traiectoriile sale conduc la comanda RETURN. Dac o traiectorie a algoritmului trimite n partea de tratare a erorilor, atunci handler-ul acesteia trebuie s includ o comand RETURN. O funcie trebuie s aib un RETURN n antet i cel puin un RETURN n partea executabil. Sintaxa simplificat pentru scrierea unei funcii este urmtoarea: [CREATE [OR REPLACE]] FUNCTION nume_funcie [(parametru[, parametru]...)] RETURN tip_de_date [DETERMINISTIC] {IS | AS} [declaraii locale] BEGIN partea executabil [EXCEPTION partea de mnuire a excepiilor] END [nume_funcie]; Opiunea tip_de_date specific tipul valorii returnate de funcie, tip care nu poate conine specificaii de mrime. Dac totui sunt necesare aceste specificaii

se pot defini subtipuri, iar parametrii vor fi declarai de subtipul respectiv. n interiorul funciei trebuie s apar RETURN expresie, unde expresie este valoarea rezultatului furnizat de funcie. Pot s fie mai multe comenzi RETURN ntr-o funcie, dar numai una din ele va fi executat, deoarece dupa ce valoarea este returnata, procesarea blocului inceteaza. Comanda RETURN (fr o expresie asociat) poate s apar i ntr-o procedur. n acest caz, ea va avea ca efect revenirea la comanda ce urmeaz instruciunii apelante. Opiunea DETERMINISTIC ajut optimizorul Oracle n cazul unor apeluri repetate ale aceleai funcii, avnd aceleai argumente. Ea asigur folosirea unui rezultat obinut anterior. n blocul PL/SQL al unei proceduri sau funcii stocate (definete aciunea efectuat de funcie) nu pot fi referite variabile host sau variabile bind. O funcie poate accepta unul sau mai muli parametri, dar trebuie s returneze o singur valoare. Ca i n cazul procedurilor, lista parametrilor este opional. Dac subprogramul nu are parametri, parantezele nu sunt necesare la declarare i la apelare. Exemplu: S se creeze o funcie stocat care determin numrul operelor de art realizate pe pnz, ce au fost achiziionate la o anumit dat. CREATE OR REPLACE FUNCTION numar_opere (v_a IN opera.data_achizitie%TYPE) RETURN NUMBER AS alfa NUMBER; BEGIN SELECT COUNT(ROWID) INTO alfa FROM opera WHERE material='panza' AND data_achizitie = v_a; RETURN alfa; END numar_opere; / Dac apare o eroare de compilare, utilizatorul o va corecta n fiierul editat i apoi va trimite fiierul modificat nucleului, cu opiunea OR REPLACE. Sintaxa pentru apelul unei funcii este: [[schema.]nume_pachet] nume_funcie [@dblink] [(lista_parametri_actuali)];

O funcie stocat poate fi apelat n mai multe moduri. 1) Apelarea funciei i atribuirea valorii acesteia ntr-o variabil de legtur iSQL*Plus: VARIABLE val NUMBER EXECUTE :val := numar_opere(SYSDATE) PRINT val Cnd este utilizat declaraia VARIABLE, pentru variabilele host de tip NUMBER nu trebuie specificat dimensiunea, iar pentru cele de tip CHAR sau VARCHAR2 valoarea implicit este 1 sau poate fi specificat o alt valoare ntre paranteze. PRINT i VARIABLE sunt comenzi iSQL*Plus. 2) Apelarea funciei ntr-o instruciune SQL: SELECT numar_opere(SYSDATE) FROM dual; 3) Apariia numelui funciei ntr-o comand din interiorul unui bloc PL/SQL (de exemplu, ntr-o instruciune de atribuire): ACCEPT data PROMPT 'dati data achizitionare' DECLARE num NUMBER; v_data opera.data_achizitie%TYPE := '&data'; BEGIN num := numar_opere(v_data); DBMS_OUTPUT.PUT_LINE('numarul operelor de arta achizitionate la data' || TO_CHAR(v_data) || este' || TO_CHAR(num)); END; / Exemplu: S se creeze o procedur stocat care pentru un anumit tip de oper de art (dat ca parametru) calculeaz numrul operelor din muzeu de tipul respectiv, numrul de specialiti care au expertizat sau au restaurat aceste opere, numrul de expoziii n care au fost expuse, precum i valoarea nominal total a acestora. CREATE OR REPLACE PROCEDURE date_tip_opera (v_tip opera.tip%TYPE) AS FUNCTION nr_opere (v_tip opera.tip%TYPE) RETURN NUMBER IS v_numar NUMBER(3); BEGIN SELECT COUNT(*) INTO v_numar

FROM opera WHERE tip = v_tip; RETURN v_numar; END; FUNCTION valoare_totala (v_tip opera.tip%TYPE) RETURN NUMBER IS v_numar opera.valoare%TYPE; BEGIN SELECT SUM(valoare) INTO v_numar FROM opera WHERE tip = v_tip; RETURN v_numar; END; FUNCTION nr_specialisti (v_tip opera.tip%TYPE) RETURN NUMBER IS v_numar NUMBER(3); BEGIN SELECT COUNT(DISTINCT studiaza.cod_specialist) INTO v_numar FROM studiaza, opera WHERE studiaza.cod_opera = opera.cod_opera AND opera.tip = v_tip; RETURN v_numar; END; FUNCTION nr_expozitii (v_tip opera.tip%TYPE) RETURN NUMBER IS v_numar NUMBER(3); BEGIN SELECT COUNT(DISTINCT figureaza_in.cod_expozitie) INTO v_numar FROM figureaza_in, opera WHERE figureaza_in.cod_opera = opera.cod_opera AND opera.tip = v_tip; RETURN v_numar; END;
BEGIN DBMS_OUTPUT.PUT_LINE('Numarul operelor de arta este '|| nr_opere(v_tip)); DBMS_OUTPUT.PUT_LINE('Valoarea oerelor de arta este '|| valoare_totala(v_tip)); DBMS_OUTPUT.PUT_LINE('Numarul de specialisti este '|| nr_specialisti(v_tip)); DBMS_OUTPUT.PUT_LINE('Numarul de expozitii este '|| nr_expozitii(v_tip); END;

Modificarea i suprimarea subprogramelor PL/SQL


Pentru a lua n considerare modificarea unei proceduri sau funcii, recompilarea acestora se face prin comanda: ALTER {FUNCTION | PROCEDURE} [schema.]nume COMPILE; Comanda recompileaz doar procedurile catalogate standard. Procedurile unui pachet se recompileaz ntr-o alt manier. Ca i n cazul tabelelor, funciile i procedurile pot fi suprimate cu ajutorul comenzii DROP. Aceasta presupune eliminarea subprogramelor din dicionarul datelor. DROP este o comand ce aparine limbajului de definire a datelor, astfel c se execut un COMMIT implicit att nainte, ct i dup comand. Cnd este ters un subprogram prin comanda DROP, automat sunt revocate toate privilegiile acordate referitor la acest subprogram. Dac este utilizat sintaxa CREATE OR REPLACE, privilegiile acordate asupra acestui obiect (subprogram) rmn aceleai. DROP {FUNCTION | PROCEDURE} [schema.]nume;

Transferarea valorilor prin parametri


Lista parametrilor unui subprogram este compus din parametri de intrare (IN), de ieire (OUT), de intrare/ieire (IN OUT), separai prin virgul. Dac nu este specificat nimic, atunci implicit parametrul este considerat IN. Un parametru formal cu opiunea IN poate primi valori implicite chiar n cadrul comenzii de declarare. Acest parametru este read-only i deci nu poate fi schimbat n corpul subprogramului. El acioneaz ca o constant. Parametrul actual corespunztor poate fi literal, expresie, constant sau variabil iniializat. Un parametru formal cu opiunea OUT este neiniializat i prin urmare, are automat valoarea NULL. n interiorul subprogramului, parametrilor cu opiunea OUT sau IN OUT trebuie s li se asigneze o valoare explicit. Dac nu se atribuie nici o valoare, atunci parametrul actual core spunztor va fi NULL. Parametrul actual trebuie s fie o variabil, nu poate fi o constant sau o expresie. Dac n procedur apare o excepie, atunci valorile parametrilor formali cu opiunile IN OUT sau OUT nu sunt copiate n valorile parametrilor actuali. Implicit, transmiterea parametrilor este prin referin n cazul parametrilor IN i este prin valoare n cazul parametrilor OUT sau IN OUT. Dac pentru realizarea unor performane se dorete transmiterea prin referin i n cazul parametrilor IN OUT sau OUT atunci se poate utiliza opiunea NOCOPY. Dac opiunea NOCOPY este asociat unui parametru IN, atunci va genera o eroare la compilare deoarece aceti parametri se transmit de fiecare dat prin referin.

10

Cnd este apelat o procedur PL/SQL, sistemul Oracle furnizeaz dou metode pentru definirea parametrilor actuali: specificarea explicit prin nume; specificarea prin poziie. Exemplu: CREATE PROCEDURE p1(a IN NUMBER, b IN VARCHAR2, c IN DATE, d OUT NUMBER) AS; Sunt prezentate diferite moduri pentru apelarea acestei proceduri. DECLARE var_a NUMBER; var_b VARCHAR2; var_c DATE; var_d NUMBER; BEGIN --specificare prin poziie p1(var_a,var_b,var_c,var_d); --specificare prin nume p1(b=>var_b,c=>var_c,d=>var_d,a=>var_a); --specificare prin nume i poziie p1(var_a,var_b,d=>var_d,c=>var_c); END; Exemplu: Fie proces_data o procedur care proceseaz n mod normal data zilei curente, dar care opional poate procesa i alte date. Dac nu se specific parametrul actual corespunztor parametrului formal plan_data, atunci acesta va lua automat valoarea dat implicit. PROCEDURE proces_data(data_in IN NUMBER, plan_data IN DATE:=SYSDATE) IS Urmtoarele comenzi reprezint apeluri corecte ale procedurii proces_data: proces_data(10); proces_data(10,SYSDATE+1); proces_data(plan_data=>SYSDATE+1,data_in=>10); O declaraie de subprogram (procedur sau funcie) fr parametri este specificat fr paranteze. De exemplu, dac procedura react_calc_dur i funcia obt_date nu au parametri, atunci: react_calc_dur; apel corect react_calc_dur(); apel incorect data_mea := obt_date; apel corect

11

Module overload
n anumite condiii, dou sau mai multe module pot s aib aceleai nume, dar s difere prin lista parametrilor. Aceste module sunt numite module overload (suprancrcate). Funcia TO_CHAR este un exemplu de modul overload. n cazul unui apel, compilatorul compar parametri actuali cu listele parametrilor formali pentru modulele overload i execut modulul corespunztor. Toate programele overload trebuie s fie definite n acelai bloc PL/SQL (bloc anonim, modul sau pachet). Nu poate fi definit o versiune ntr-un bloc, iar alt versiune ntr-un bloc diferit. Modulele overload pot s apar n programele PL/SQL fie n seciunea declarativ a unui bloc, fie n interiorul unui pachet. Suprancrcarea funciilor sau procedurilor nu se poate face pentru funcii sau proceduri stocate, dar se poate face pentru subprograme locale, subprograme care apar n pachete sau pentru metode. Observaii: Dou programe overload trebuie s difere, cel puin, prin tipul unuia dintre parametri. Dou programe nu pot fi overload dac parametri lor formali difer numai prin subtipurile lor i dac aceste subtipuri se bazeaz pe acelai tip de date. Nu este suficient ca lista parametrilor programelor overload s difere numai prin numele parametrilor formali. Nu este suficient ca lista parametrilor programelor overload s difere numai prin tipul acestora (IN, OUT, IN OUT). PL/SQL nu poate face diferene (la apelare) ntre tipurile IN sau OUT. Nu este suficient ca funciile overload s difere doar prin tipul datei returnate (tipul datei specificate n clauza RETURN a funciei). Exemplu: Urmtoarele subprograme nu pot fi overload. a) FUNCTION alfa(par IN POSITIVE); FUNCTION alfa(par IN BINARY_INTEGER); b) FUNCTION alfa(par IN NUMBER); FUNCTION alfa(parar IN NUMBER); c) PROCEDURE beta(par IN VARCHAR2) IS; PROCEDURE beta(par OUT VARCHAR2) IS;

12

Exemplu: S se creeze dou funcii (locale) cu acelai nume care s calculeze media valorilor operelor de art de un anumit tip. Prima funcie va avea un argument reprezentnd tipul operelor de art, iar cea de a doua va avea dou argumente, unul reprezentnd tipul operelor de art, iar cellalt reprezent nd stilul operelor pentru care se calculeaz valoarea medie (adic funcia va calcula media valorilor operelor de art de un anumit tip i care aparin unui stil specificat). DECLARE medie1 NUMBER(10,2); medie2 NUMBER(10,2); FUNCTION valoare_medie (v_tip opera.tip%TYPE) RETURN NUMBER IS medie NUMBER(10,2); BEGIN SELECT AVG(valoare) INTO medie FROM opera WHERE tip = v_tip; RETURN medie; END; FUNCTION valoare.medie (v_tip opera.tip%TYPE, v_stil opera.stil%TYPE) RETURN NUMBER IS medie NUMBER(10,2); BEGIN SELECT AVG(valoare) INTO medie FROM opera WHERE tip = v_tip AND stil = v_stil; RETURN medie; END; BEGIN medie1 := valoare_medie('pictura'); DBMS_OUTPUT.PUT_LINE(Media valorilor picturilor din muzeu este || medie1); medie2 := valoare_medie('pictura', 'impresionism'); DBMS_OUTPUT.PUT_LINE(Media valorilor picturilor impresioniste din muzeu este ' || medie2); END;

13

Procedur versus funcie


Pot fi marcate cteva deosebiri eseniale ntre funcii i proceduri. Procedura se execut ca o comand PL/SQL, iar funcia se invoc ca parte a unei expresii. Procedura poate returna (sau nu) una sau mai multe valori, iar func ia trebuie s returneze (cel putin) o singur valoare. Procedura nu trebuie s conin RETURN tip_date, iar funcia trebuie s conin aceast opiune. De asemenea, pot fi marcate cteva elemente eseniale, comune att funciilor ct i procedurilor. Ambele pot: accepta valori implicite; avea seciuni declarative, executabile i de tratare a erorilor; utiliza specificarea prin nume sau poziie a parametrilor; pot accepta parametri NOCOPY.

Recursivitate
Un subprogram recursiv presupune c acesta se apeleaz pe el nsui. n Oracle o problem delicat este legat de locul unde se plaseaz un apel recursiv. De exemplu, dac apelul este n interiorul unui cursor FOR sau ntre comenzile OPEN i CLOSE, atunci la fiecare apel este deschis alt cursor. n felul acesta, programul poate depi limita pentru OPEN_CURSORS setat n parametrul de iniializare Oracle. Exemplu: S se calculeze recursiv al m-lea termen din irul lui Fibonacci. CREATE OR REPLACE FUNCTION fibona(m number:=5) RETURN INTEGER IS BEGIN IF (m = 1) OR (m = 2) THEN RETURN 1; ELSE RETURN fibona(m-1) + fibona(m-2); END IF; END fibona;

Declaraii forward
Subprogramele sunt reciproc recursive dac ele se apeleaz unul pe altul direct sau indirect. Declaraiile forward permit definirea subprogramelor reciproc

14

recursive. n PL/SQL, un identificator trebuie declarat nainte de a-l folosi. De asemenea, un subprogram trebuie declarat nainte de a-l apela. PROCEDURE alfa ( ... ) IS BEGIN beta( ... ); -- apel incorect ... END; PROCEDURE beta ( ... ) IS BEGIN ... END; Procedura beta nu poate fi apelat deoarece nu este nc declarat. Problema se poate rezolva simplu, inversnd ordinea celor dou proceduri. Aceast soluie nu este eficient ntotdeauna. PL/SQL permite un tip special de declarare a unui subprogram numit forward. El const dintr-o specificare de subprogram terminat prin ;. PROCEDURE beta ( ... ); -- declaraie forward .. PROCEDURE alfa ( ... ) IS BEGIN beta( ... ); ... END; PROCEDURE beta ( ... ) IS BEGIN ... END; Se pot folosi declaraii forward pentru a defini subprograme ntr-o anumit ordine logic, pentru a defini subprograme reciproc recursive, pentru a grupa subprograme ntr-un pachet. Lista parametrilor formali din declaraia forward trebuie s fie identic cu cea corespunztoare corpului subprogramului. Corpul subprogramului poate aprea oriunde dup declaraia sa forward, dar trebuie s rmn n aceeai unitate de program.

Utilizarea n expresii SQL a funciilor definite de utilizator


ncepnd cu Release 7.1, o funcie stocat poate fi referit ntr-o comand SQL la fel ca orice funcie standard furnizat de sistem (built-in function), dar cu anumite restricii. Funciile PL/SQL definite de utilizator pot fi apelate din orice

15

expresie SQL n care pot fi folosite funcii SQL standard. Funciile PL/SQL pot s apar n: lista de selecie a comenzii SELECT; condiia clauzelor WHERE i HAVING; clauzele CONNECT BY, START WITH, ORDER BY i GROUP BY; clauza VALUES a comenzii INSERT; clauza SET a comenzii UPDATE. Exemplu: S se afieze operele de art (titlu, valoare, stare) a cror valoare este mai mare dect valoarea medie a tuturor operelor de art din muzeu. CREATE OR REPLACE FUNCTION valoare_medie RETURN NUMBER IS v_val_mediu opera.valoare%TYPE; BEGIN SELECT AVG(valoare) INTO v_val_mediu FROM opera; RETURN v_val_mediu; END; Referirea acestei funcii ntr-o comanda SQL se poate face prin: SELECT titlu, valoare, stare FROM opera WHERE valoare >= valoare_medie; Exist restricii referitoare la folosirea funciilor definite de utilizator ntr-o comand SQL. funcia definit de utilizator trebuie s fie o funcie stocat (procedurile stocate nu pot fi apelate n expresii SQL), nu poate fi local unui alt bloc; funcia apelat dintr-o comand SELECT, sau din comenzi paralelizate INSERT, UPDATE i DELETE nu poate contine comenzi LMD care modifica tabelele bazei de date; funcia apelat dintr-o comand UPDATE sau DELETE nu poate interoga sau modifica tabele ale bazei reactualizate chiar de aceste comenzi (table mutating); funcia apelat din comenzile SELECT, INSERT, UPDATE sau DELETE nu poate executa comenzi LCD (COMMIT), ALTER SYSTEM, SET ROLE

16

sau comenzi LDD (CREATE); funcia nu poate s apar n clauza CHECK a unei comenzi CREATE/ALTER TABLE; funcia nu poate fi folosit pentru a specifica o valoare implicit pentru o coloan n cadrul unei comenzi CREATE/ALTER TABLE; funcia poate fi utilizat ntr-o comand SQL numai de ctre proprietarul funciei sau de utilizatorul care are privilegiul EXECUTE asupra acesteia; funcia definit de utilizator, apelabil dintr-o comand SQL, trebuie s aib doar parametri de tip IN, cei de tip OUT i IN OUT nefiind acceptai; parametrii unei funcii PL/SQL apelate dintr-o comand SQL trebuie s fie specificai prin poziie (specificarea prin nume nefiind permis); parametrii formali ai unui subprogram funcie trebuie s fie de tip specific bazei de date (NUMBER, CHAR, VARCHAR2, ROWID, LONG, LONGROW, DATE), nu tipuri PL/SQL (BOOLEAN sau RECORD); tipul returnat de un subprogram funcie trebuie s fie un tip intern pentru server, nu un tip PL/SQL (nu poate fi TABLE, RECORD sau BOOLEAN); funcia nu poate apela un subprogram care nu respect restriciile anterioare. Exemplu: CREATE OR REPLACE FUNCTION calcul (p_val NUMBER) RETURN NUMBER IS BEGIN INSERT INTO opera(cod_opera, tip, data_achizitie, valoare); VALUES (1358, 'gravura', SYSDATE, 700000); RETURN (p_val*7); END; / UPDATE SET WHERE opera valoare = calcul (550000) cod_opera = 7531;

Comanda UPDATE va returna o eroare deoarece tabelul opera este mutating. Reactualizarea este insa permisa asupra oricarui alt tabel diferit de opera.

17

Informaii referitoare la subprograme


Informaiile referitoare la subprogramele PL/SQL i modul de acces la aceste informaii sunt urmtoarele: codul surs, utiliznd vizualizarea USER_SOURCE din dicionarul datelor (DD); informaii generale, utiliznd vizualizarea USER_OBJECTS din dicionarul datelor; tipul parametrilor (IN, OUT, IN OUT), utiliznd comanda DESCRIBE din iSQL*Plus; p-code (nu este accesibil utilizatorilor); erorile la compilare, utiliznd vizualizarea USER_ERRORS din dicionarul datelor sau comanda SHOW ERRORS din iSQL*Plus; informaii de depanare, utiliznd pachetul DBMS_OUTPUT. Vizualizarea USER_OBJECTS conine informaii generale despre toate obiectele manipulate n BD, n particular i despre subprogramele stocate. Vizualizarea USER_OBJECTS are urmtoarele cmpuri: OBJECT_NAME numele obiectului; OBJECT_TYPE, tipul obiectului (PROCEDURE, FUNCTION etc.); OBJECT_ID identificator intern al obiectului; CREATED data cnd obiectul a fost creat; LAST_DDL_TIME data ultimei modificri a obiectului; TIMESTAMP data i momentul ultimei recompilri; STATUS starea obiectului (VALID sau INVALID). Pentru a verifica dac recompilarea explicit (ALTER) sau implicit a avut succes se poate verifica starea subprogramelor utiliznd USER_OBJECTS. Orice obiect are o stare (status) sesizat n DD, care poate fi: VALID (obiectul a fost compilat i poate fi folosit cnd este referit); INVALID (obiectul trebuie compilat nainte de a fi folosit). Exemplu: S se listeze procedurile i funciile deinute de utilizatorul curent, precum i starea acestora.

18

SELECT OBJECT_NAME, OBJECT_TYPE, STATUS FROM USER_OBJECTS WHERE OBJECT_TYPE IN (PROCEDURE,FUNCTION); Dup ce subprogramul a fost creat, codul surs al acestuia poate fi obinut consultnd vizualizarea USER_SOURCE din DD, care are urmtoarele cmpuri: NAME numele obiectului; TYPE tipul obiectului; LINE numrul liniei din codul surs; TEXT textul liniilor codului surs. Exemplu: S se afieze codul complet pentru funcia numar_opere. SELECT TEXT FROM USER_SOURCE WHERE NAME = numar_opere ORDER BY LINE; Exemplu: S se scrie o procedur care recompileaz toate obiectele invalide din schema personal. CREATE OR REPLACE PROCEDURE sterge IS CURSOR obj_curs IS SELECT OBJECT_TYPE, OBJECT_NAME FROM USER_OBJECTS WHERE STATUS = 'INVALID' AND OBJECT_TYPE IN ('PROCEDURE', 'FUNCTION', PACKAGE', 'PACKAGE BODY', 'VIEW'); BEGIN FOR obj_rec IN obj_curs LOOP DBMS_DDL.ALTER_COMPILE(obj_rec.OBJECT_TYPE, USER, obj_rec.OBJECT_NAME); END LOOP; END sterge; Dac se recompileaz un obiect PL/SQL, atunci server-ul va recompila orice obiect invalid de care depinde. Dac recompilarea automat implicit a procedurilor locale dependente are probleme, atunci starea obiectului va rmne INVALID i server-ul Oracle semnaleaz eroare. Prin urmare: este preferabil ca recompilarea s fie manual (recompilare explicit utiliznd comanda ALTER (PROCEDURE, FUNCTION, TRIGGER, PACKAGE) cu opiunea COMPILE;

19

este necesar ca recompilarea s se fac ct mai repede, dup definirea unei schimbri referitoare la obiectele bazei. Pentru a obine valori (de exemplu, valoarea contorului pentru un LOOP, valoarea unei variabile nainte i dup o atribuire etc.) i mesaje (de exemplu, prsirea unui subprogram, apariia unei operaii etc.) dintr-un bloc PL/SQL pot fi utilizate procedurile pachetului DBMS_OUTPUT. Aceste informaii se cumuleaz ntr-un buffer care poate fi consultat.