Oracle
 sql >> база данни >  >> RDS >> Oracle

ORA-6502 с тригер за регистриране на разрешение

Имам нов проект, върху който работя, където искам да имам работа на Oracle, която да отменя привилегиите, които дадох на ИТ персонала, който е по-стар от 30 дни. Нашият ИТ персонал се нуждае от периодичен достъп до няколко производствени таблици, за да отстранява проблеми. Предоставяме SELECT privs на масите, от които човек се нуждае, но никой никога не ми казва кога е приключил със задачата си и тези привилегии остават там завинаги. Исках да имам система да отменя автоматично привилегии, по-стари от 30 дни, за да не се налага да си спомням да го направя. Преди да мога да отменя привилегиите, имах нужда от начин за проследяване на тези привилегии. Така че създадох тригер, който се задейства всеки път, когато се издава GRANT и записва подробностите в таблица. По-късно задача на Oracle ще сканира тази таблица и ще отмени привилегиите, които установи, че са твърде стари. Моят тригерен код е както следва:

create or replace trigger sys.grant_logging_trig after grant on database
  declare
    priv  dbms_standard.ora_name_list_t;
    who   dbms_standard.ora_name_list_t;
    npriv pls_integer;
    nwho  pls_integer;
  begin
    npriv := ora_privilege_list(priv);
    if (ora_sysevent = 'GRANT') then
      nwho := ora_grantee(who);
    else
      nwho := ora_revokee(who);
    end if;
     for i in 1..npriv
     loop
       for j in 1..nwho
       loop  
        insert into system.grant_logging values
          ( systimestamp,
            ora_login_user,
            ora_sysevent,
            who(j),
            priv(i),
            ora_dict_obj_owner,
            ora_dict_obj_name
          );
      end loop;
    end loop; 
end;
 / 

Кодът по-горе не е оригинален. Намерих добър пример в интернет и промених няколко неща. След като тествах кода в продължение на 3 седмици, пуснах спусъка в производство. Отне ми само няколко дни, за да получа грешка.

SQL> CREATE USER bob IDENTIFIED BY password;

ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-04088: error during execution of trigger 'SYS.GRANT_LOGGING_TRIG'
ORA-00604: error occurred at recursive SQL level 2
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at line 28

Хммм... Създавам потребител, който не предоставя нищо. Но можем със сигурност да видим, че спусъкът ми има проблем с изпълнението. Така че защо се задейства този спусък, ако всичко, което правя, е да създавам потребител? Проста SQL проследяване ми показа какво се случва с този рекурсивен SQL. Зад кулисите Oracle издава следното от мое име:

ПРЕДОСТАВЯТЕ ПРИВИЛЕГИИ ЗА НАСЛЕДЯВАНЕ НА ПОТРЕБИТЕЛЯ „BOB“ на ПУБЛИЧНО;

Добре… в този момент знам, че се издава GRANT, когато създам потребител, но защо това се проваля? Тествах този тригер със системни привилегии и работи добре. Разбира се, не тествах НАСЛЕДВАНИ ПРИВИЛЕГИИ, така че това е един вид краен случай.

След доста усилия за отстраняване на грешки установих, че извикването на функцията ora_privilege_list връща празен набор към колекцията, наречена „priv“. Като такъв, npriv се настройва на стойност NULL. Тъй като NPRIV е NULL, реда, където се казва „за i в 1..npriv“, няма много смисъл, оттук и грешката.

Според мен ora_privilege_list трябва да върне един елемент, „НАСЛЕДЯВАТЕ ПРИВИЛЕГИИ“ и смятам, че не връща този списък като грешка. Въпреки това, ако ora_privilege_list ще върне празна колекция, тогава изходът от функцията трябва да бъде нула и тогава npriv ще получи по-правилна стойност. За образователни цели ora_privilege_list е синоним на DBMS_STANDARD.PRIVILEGE_LIST.

Като се има предвид всичко това, не мога да контролирам функцията Oracle. И не искам да чакам Oracle да промени кода си в DBMS_STANDARD до това, което мисля, че трябва да бъде. Така че просто ще кодирам своя спусък, за да се справя с проблема. Добавянето на два прости реда реши проблема ми (виждан по-долу с удебелен шрифт).

create or replace trigger sys.grant_logging_trig after grant on database
  declare
    priv  dbms_standard.ora_name_list_t;
    who   dbms_standard.ora_name_list_t;
    npriv pls_integer;
    nwho  pls_integer;
  begin
    npriv := ora_privilege_list(priv);
    if (ora_sysevent = 'GRANT') then
      nwho := ora_grantee(who);
    else
      nwho := ora_revokee(who);
    end if;
   if to_char(npriv) is not null then 
     for i in 1..npriv
     loop
       for j in 1..nwho
       loop  
        insert into system.grant_logging values
          ( systimestamp,
            ora_login_user,
            ora_sysevent,
            who(j),
            priv(i),
            ora_dict_obj_owner,
            ora_dict_obj_name
          );
      end loop;
    end loop; 
  end if;
end;
 / 

Така че поправката е доста проста. Изпълнете двата цикъла FOR само ако NPRIV не е нула.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle – Какъв файл с имена на TNS използвам?

  2. JDBC ResultSet получава колони с псевдоним на таблица

  3. Oracle:OALL8 е в непоследователно състояние

  4. Oracle Big Data SQL

  5. Вмъкване на данни в базата данни на Oracle с помощта на php