Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
Schematu HR.
Jeśli chcemy trochę elastyczności w naszym systemie - to nie ma jak dynamiczny SQL!
Ale czasem dynamiczny SQL odmawia współpracy. Mimo, że mamy nadane wszystkie potrzebne uprawniania - otrzymujemy błąd:
ORA-01031: insufficient privileges
Sprawdźmy, jaka może być tego przyczyna i jak możemy rowiązać problem z brakiem uprawnień.
Chcemy przygotować skrypt, który utworzy dynamicznie tabelkę tab_dyn.
declare vsql varchar2(32000); begin vsql := 'create table tab_dyn (id number)'; DBMS_OUTPUT.put_line(vsql); execute immediate vsql; exception when others then DBMS_OUTPUT.put_line(sqlerrm); end; /
select * from tab_dyn; no rows selected
Przetestowane, wszystko działa. Możemy więc nasz anonimowy blok zapisać w postaci procedury.
drop table tab_dyn; create or replace procedure proc_dyn is vsql varchar2(32000); begin vsql := 'create table tab_dyn (id number)'; DBMS_OUTPUT.put_line(vsql); execute immediate vsql; exception when others then DBMS_OUTPUT.put_line(sqlerrm); end; /
Uruchamiamy procedurkę:
exec proc_dyn;
i?
create table tab_dyn (id number) ORA-01031: insufficient privileges PL/SQL procedure successfully completed.
Niewystarczające uprawnienia? Ale jak to? Przed chwilą działało :o
Problem polega na tym, że jeśli chcemy wykorzystywać dynamiczny SQL - uprawnienia do obiektów musimy nadać bezpośrednio, nie przez rolę. W tym przypadku musimy użytkownikowi HR nadać uprawnienie CREATE ANY TABLE.
-- sys grant create any table to hr;
I spróbujmy jeszcze raz:
exec proc_dyn; select * from tab_dyn; no_rows_selected
Tym razem działa.
Innym rozwiązaniem jest utworzenie procedury z uprawnieniami AUTHID CURRENT_USER.
Usuniemy uprawnienia i skasujemy tabelę:
revoke create any table from hr; drop table tab_dyn;
Utworzony jeszcze raz procedurę proc_dyn.
create or replace procedure proc_dyn AUTHID CURRENT_USER is vsql varchar2(32000); begin vsql := 'create table tab_dyn (id number)'; DBMS_OUTPUT.put_line(vsql); execute immediate vsql; exception when others then DBMS_OUTPUT.put_line(sqlerrm); end; /
Czas na test:
exec proc_dyn; select * from tab_dyn; no_rows_selected
Działa :)
Komentarze
Prześlij komentarz