sql >> Databasteknik >  >> RDS >> Oracle

ORA-6502 med Grant Logging Trigger

Jag har ett nytt projekt som jag arbetar med där jag vill att ett Oracle-jobb ska återkalla privilegier som jag beviljat IT-personal som är äldre än 30 dagar. Vår IT-personal behöver då och då tillgång till några produktionstabeller för att felsöka problem. Vi ger SELECT privilegier på borden som personen behöver, men ingen berättar någonsin för mig när de är klara med sin uppgift och de privilegierna sitter där ute för alltid. Jag ville ha ett system som automatiskt återkallar privilegier äldre än 30 dagar så att jag inte skulle behöva komma ihåg att göra det. Innan jag kunde återkalla privilegier behövde jag ett sätt att spåra dessa privilegier. Så jag skapade en trigger som aktiveras när ett GRANT utfärdas och loggar detaljerna till en tabell. Senare kommer ett Oracle-jobb att skanna tabellen och återkalla privilegier som det upptäcker som är för gamla. Min triggerkod är följande:

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;
 / 

Koden ovan är inte original. Jag hittade ett bra exempel på Internet och ändrade några saker. Efter att ha testat koden i 3 veckor satte jag avtryckaren i produktion. Det tog bara några dagar innan jag fick ett felmeddelande.

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

Hmmm...jag skapar en användare som inte beviljar något. Men vi kan säkert se att min trigger har problem med att köra. Så varför utlöses den här utlösaren om allt jag gör är att skapa en användare? En enkel SQL-spårning visade mig vad som hände med den rekursiva SQL. Bakom kulisserna utfärdar Oracle följande för mina räkningar:

GE ÄRV PRIVILEGIER PÅ ANVÄNDAREN "BOB" till PUBLIC;

Ok...så vid det här laget vet jag att det utfärdas ett GRANT när jag skapar en användare men varför misslyckas detta? Jag testade den här utlösaren med systemprivilegier och det fungerade bra. Visst, jag testade inte ÄRVLIGA PRIVILEGIER, så det här är ett slags kantfall.

Efter en stor del av felsökningsansträngningen fastställde jag att funktionsanropet ora_privilege_list returnerar en tom uppsättning till samlingen med namnet "priv". Som sådan sätts npriv till ett NULL-värde. Eftersom NPRIV är NULL, är raden där det står "för i i 1..npriv" inte mycket meningsfullt, därav felet.

Enligt min åsikt bör ora_privilege_list returnera ett objekt, "ARV PRIVILEGES" och jag tror att det inte returnerar den listan som en bugg. Men om ora_privilege_list ska returnera en tom samling, bör utdata från funktionen vara noll och då skulle npriv få ett mer korrekt värde. I utbildningssyfte är ora_privilege_list en synonym för DBMS_STANDARD.PRIVILEGE_LIST.

Med detta sagt kan jag inte kontrollera Oracle-funktionen. Och jag vill inte vänta på att Oracle ska ändra sin kod i DBMS_STANDARD till vad jag tycker att den borde vara. Så jag kommer bara att koda min trigger för att hantera problemet. Att lägga till två enkla rader löste mitt problem (se nedan i fet stil).

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;
 / 

Så åtgärden är ganska enkel. Utför endast de två FOR-slingorna om NPRIV inte är null.


  1. ATAN() Exempel i SQL Server

  2. Bevilja alla på ett specifikt schema i db till en grupproll i PostgreSQL

  3. Migrera från Oracle till PostgreSQL - Vad du bör veta

  4. Skapa en databas i SQL Server 2017