Pe parametrii apelantului și de ieșire în Oracle

Cel mai bun din experiența practică de utilizare a drepturilor inițiatorul apelului și funcțiile.

Întrebare: Operatorul AUTHID CURRENT_USER Recent, am multe ori folosit (dreapta drepturi invocatorul inițiator al apelului). de multe ori am scrie instrumente pentru alți dezvoltatori în echipa mea și să le definească într-o schemă de SHARED_CODE centrală. Când am defini un program cu drepturile apelantului, toți dezvoltatorii pot apela acest program și se va realiza în mod automat operațiile dorite pe acele obiecte care sunt în schema proprie a dezvoltatorului. Dar, uneori, am rula în probleme legate de drepturile inițiatorului. În următorul proiect, trebuie să lucrăm cu fișierele de sistem de operare prin UTL_FILE. În special, vom scrie textul în fișierele, iar textul ar trebui să fie formatat într-o varietate de forme. Așa că am decis să scrie o „scrie în fișier“, care va efectua toate operațiunile cu UTL_FILE, și permite utilizatorilor să specifice formatarea cu propriile lor funcții. Astfel, ei vor avea o flexibilitate maximă pentru formatare. Dar acest lucru nu pare să funcționeze. Am scris un program de „scrie în fișier“ cu drepturi invocatorul, dar ea refuză să cheme programul inițiator de formatare. Care este eroarea?

Răspuns: Nu există nici o eroare. Tocmai ai întâlnit la limitarea drepturilor inițiatorului apelului. Din fericire, eu pot ajuta să lucrați în jurul valorii de această limitare și pentru a atinge dorit.

De obicei, tot ce este necesar este de a scrie programul principal, care returnează controlul la rutina al cărui nume nu este încă cunoscut la scrierea programului. Astfel, programul ar trebui în timpul unui apel pentru a înțelege care a provocat programul.

Unul dintre modurile în care puteți utiliza mecanismul de retur este utilizarea polimorfismului dinamic și tipuri de obiecte Oracle. Acesta este modul cel mai convenabil, care trebuie să fie abordate într-un alt moment. Și de data asta vă voi arăta cum puteți utiliza în continuare revine și drepturile inițiatorul apelului pentru a obține rezultatul dorit.

Să începem cu unele dintre principiile drepturilor invocatorul care se aplică tuturor SQL propuneri (atât statice și dinamice), efectuate în PL / SQL-bloc. În drepturile invocatorul de aplicare, numele de regiuni și de calcul privilegiul corespunzător are loc în timpul apelului (mai târziu rolurile sunt recunoscute și utilizate pentru a calcula aceste privilegii). legea apelantului aplică următoarele propuneri:
  • Sugestii pentru manipulare a datelor SELECT, INSERT, UPDATE și DELETE
  • Propunere de gestionare a tranzacției LOCK TABLE
  • Propunerile pentru a controla cursorul deschis si deschis-FOR
  • Toate SQL propuneri dinamice (EXECUTE IMMEDIATE, DESCHISĂ și DBMS_SQL)

Să presupunem că includ clauza AUTHID CURRENT_USER în antetul programului meu. Când am compila acest program, sistemul actual încă mai avea nevoie de privilegii acordate în mod direct de pe toate obiectele care se face referire în program.

Una dintre concluzii evidente care pot fi trase din aceasta este că declarația AUTHID CURRENT_USER nu s-ar aplica apelurilor statice alte rutine apelate de programe cu drepturi invocatorul.

Programul de apel static atunci când programul este determinat la momentul compilarii. De exemplu, următorul fragment de cod, PROC1 cauzează proc2 static.

În timpul proc1 compilare în schema ABC, Oracle Database permite o legătură cu relația proc2 cu privilegiile acestui sistem. Acum, să presupunem că baza de date caută procedura proc2 la schema ABC. Grant privilegiul EXECUTE la ABC.proc1 unui alt sistem, cum ar fi DEF, care are propria sa procedură proc2. Atunci când un utilizator se conectează la DEF executa ABC.proc1, utilizatorul respectiv va rula întotdeauna ABC.proc2, nu DEF.proc2.

Asta înseamnă că este imposibil de a crea un program de lucru „scrie în fișier“ cu drepturi invocatorul? Nu chiar. Puteți obține de fapt, Oracle pentru a selecta în mod dinamic pe care programul ar trebui să sune, dar este necesar să se aplice posibilitatea de dinamică PL / SQL.

Luați în considerare două demonstrații simple ale impactului drepturilor invocatorul, iar apoi voi arăta dinamic PL / SQL- „ocolind“

În primul rând, ia în considerare authId Utilizatorul curent în ceea ce privește obiectele de date. Listarea 1 în Schema HR drepturi create procedură apel show_my_data inițiator care arată numărul de rânduri în tabel tabel my_data (10). Emitem privilegiul EXECUTE utilizator SCOTT pentru a invoca programul. au, de asemenea, un tabel my_data, în cazul în care o linie în schema SCOTT. Apoi SCOTT cauzele HR.show_my_data, iar programul afișează un 1 în loc de 10 linii.

Listarea 1: Crearea și apelarea show_my_data

După cum puteți vedea, în ciuda faptului că am fugit procesul show_my_data HR, programul mi arată numărul de tabelă utilizator my_data SCOTT.

Dar acum să încercăm să creeze o „scriere în fișier“. În primul rând, „implicit“ va crea un director de bază de date a funcției de utilizator HR și formatul (text convertit în litere mari):

Apoi, creați un program foarte simplu, se arată în Listarea 2, care efectuează o „scrie la dosar“, și să dea utilizatorul SCOTT poate apela.

Listarea 2: Crearea write_to_file

Apoi se alăture ca SCOTT, de a crea funcția de formatare care se traduce textul în litere mici, și de apel write_to_file așa cum se arată în Listarea 3.

Listarea 3: Crearea format_line (și provocarea write_to_file)

Din păcate, am primit următorul myfile.txt de text în fișierul de ieșire:

Deci, nu foarte probabil că am putea folosi apelul de inițiator de program corect? Ei bine, poate încerca un alt mod: folosind SQL dinamic.

Am rescris programul write_to_file original în HR, așa cum se arată în Listarea 4.

Listarea 4: Crearea unui write_to_file modificat

Rețineți că m-am mutat provocarea funcțiile format_line oferă EXECUTE IMMEDIATE. Așa că am sunat funcția de dinamica PL / SQL-bloc. Și acum mă alătur ca SCOTT și apel write_to_file:

Și aici vedem următorul cuprins în myfile.txt fișier de ieșire:

Oh, funcționează! Este posibil?

Mutarea apelului într-un program de PL / SQL-bloc executat dinamic, apelul a devenit realizat din propunere, care poate fi aplicat dreptul apelantului: EXECUTE IMMEDIATE. Astfel, unitatea este acum execută sub SCOTT“, deoarece acesta este numit versiune format_line utilizator SCOTT.

Prin urmare, este corect ca inițiator al apelului poate fi utilizat pentru a efectua stiva de apel folosind dinamic PL / SQL.

Rețineți, vă rugăm, că performanța dinamică a PL / SQL rutine mai lent decât statice. Pentru programe de lungă durată, aceste costuri vor fi nesemnificative, dar păstrează acest lucru în minte atunci când crearea de programe care sunt finalizate foarte repede.

Am comparat performanta de pornire static și dinamic al programului, care apelează USER și stochează această valoare într-o variabilă locală. The Run 100.000 de ori folosind un apel statică este efectuată timp de 2,83 secunde. Lansarea dinamică se realizează în 6,66 secunde.

O ultimă notă: O modalitate alternativă de a obține același efect (alegerea programului pentru a rula în timpul funcționării), este utilizarea polimorfismului dinamic. Această tehnică este construit în tipurile de obiecte în PL / SQL și anume, prin stabilirea unei ierarhii de tipuri de obiecte cu cuvântul cheie SUB. Pentru mai multe informații despre tipuri de obiecte și polimorfismul dinamic în PL / SQL, studiul Capitolul 12, „Folosirea PL / SQL cu tipuri de obiecte“, în Ghidul Oracle Database PL SQL utilizator / și de referință.

Î: Eu cred că funcția trebuie să returneze datele numai printr-o declarație de returnare. De ce PL / SQL vă permite să utilizați OUT-parametrii în funcții? Poate în utilizarea acestei funcții are o anumită specificitate?

A: Am format unele îndrumări cu privire la structura funcției:
  • Nu utilizați sau în afară argumente în lista de parametri ai funcției.
  • Returnează toate datele din instrucțiunea RETURN.
  • Coda doar o singură declarație RETURN în funcția realizată o parte si face ultima linie din această secțiune.
  • În cazul în care este necesar să se întoarcă mai multe valori pot fi utilizate ca tipurile de date compozit (înregistrare de colectare obiect, și altele asemenea), și de a schimba funcția în cadrul procedurii, și apoi utilizați OUT sau în argumentul OUT.

De ce Oracle ne permite să folosim out-argumente în funcțiile listei de parametri? Probabil pentru că ea recunoaște că lumea nu ca alb-negru, și creează o mulțime de nuanțe de gri. Programatorii au o mai mare libertate de alegere, cu multe stiluri diferite de scrierea de cod.

Sunt foarte mulțumit de faptul că Oracle nu renunta la practica de utilizare a parametrilor OUT-funcției (care nu este, de altfel, universal acceptată și practica comună în lumea de programare) în punerea în aplicare a PL / SQL.

Experiențele mele cu lumea de programare în C, de exemplu, arată că dezvoltatorii scrie de obicei, o funcție care returnează un cod de retur care indică dacă funcția este finalizată cu succes. Ei folosesc apoi OUT-argumente în lista de parametri pentru a reveni informații din funcția.

Nu-mi place această abordare, mai ales în PL / SQL, dar eu simt că am nevoie de o mai mare flexibilitate de limbă, nu mai puțin. Și trebuie să dezvolte propria tehnologie personalizate pentru a alege care PL / SQL capabilități de utilizat și care nu sunt.

Desigur, pot exista situații în care funcția cu OUT-parametru util. Luați în considerare următorul bloc. Funcția source_code.more_data returnează Boolean, care este folosit pentru a ieși din bucla și returnează la fel ca OUT-argument o structură de date care sunt apoi prelucrate într-o buclă.

Da, desigur, pot rescrie codul astfel încât să utilizeze funcția fără OUT-parametru sau o procedură, dar va face codul mai ciudat și dificil de citit.

Prin urmare, noi în mod clar nu doresc să facă funcții Oracle cu OUT sau IN OUT parametru este invalid, dar cred că această listă de opțiuni devine utilă numai în anumite situații.