sql >> Database teknologi >  >> RDS >> Oracle

ORA-6502 med Grant Logging Trigger

Jeg har et nyt projekt, jeg arbejder på, hvor jeg vil have et Oracle-job til at tilbagekalde privilegier, jeg har givet til it-medarbejdere, der er ældre end 30 dage. Vores it-medarbejdere har brug for lejlighedsvis adgang til nogle få produktionstabeller for at fejlfinde problemer. Vi giver SELECT privs på bordene, den person har brug for, men ingen fortæller mig nogensinde, hvornår de er færdige med deres opgave, og disse privilegier sidder derude for evigt. Jeg ville have et system til automatisk at tilbagekalde privilegier, der er ældre end 30 dage, så jeg ikke skulle huske at gøre det. Før jeg kunne tilbagekalde privilegier, havde jeg brug for en måde at spore disse privilegier på. Så jeg oprettede en trigger, der udløses, når der udstedes et GRANT, og logger detaljerne til en tabel. Senere vil et Oracle-job scanne den tabel og tilbagekalde privilegier, det finder, som er for gamle. Min triggerkode er som følger:

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

Ovenstående kode er ikke original. Jeg fandt et godt eksempel på internettet og ændrede et par ting. Efter at have testet koden i 3 uger, rullede jeg aftrækkeren i produktion. Det tog kun et par dage for mig at modtage en fejl.

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...Jeg opretter en bruger, der ikke giver noget. Men vi kan med sikkerhed se, at min trigger har et problem med at udføre. Så hvorfor udløses denne trigger, hvis alt, hvad jeg gør, er at oprette en bruger? En simpel SQL-sporing viste mig, hvad der foregik med den rekursive SQL. Bag kulisserne udsender Oracle følgende på mine vegne:

GIV ARV PRIVILEGIER TIL BRUGER "BOB" til OFFENTLIG;

Ok...så på dette tidspunkt ved jeg, at der udstedes et GRANT, når jeg opretter en bruger, men hvorfor mislykkes dette? Jeg testede denne trigger med systemrettigheder, og det fungerede fint. Indrømmet, jeg testede ikke ARVE PRIVILEGIER, så det her er en slags kantsag.

Efter en god mængde fejlfindingsindsats fandt jeg ud af, at ora_privilege_list funktionskaldet returnerer et tomt sæt til samlingen med navnet "priv". Som sådan bliver npriv sat til en NULL-værdi. Fordi NPRIV er NULL, giver linjen hvor der står "for i in 1..npriv" ikke meget mening, derfor fejlen.

Efter min mening bør ora_privilege_list returnere ét element, "ARV PRIVILEGES", og jeg mener, at det ikke returnerer denne liste til at være en fejl. Men hvis ora_privilege_list kommer til at returnere en tom samling, så burde outputtet fra funktionen være nul, og så ville npriv få en mere korrekt værdi. Til uddannelsesformål er ora_privilege_list et synonym for DBMS_STANDARD.PRIVILEGE_LIST.

Når det er sagt, kan jeg ikke kontrollere Oracle-funktionen. Og jeg vil ikke vente på, at Oracle ændrer deres kode i DBMS_STANDARD til, hvad jeg synes, den burde være. Så jeg vil bare kode min trigger for at håndtere problemet. Tilføjelse af to enkle linjer løste mit problem (se nedenfor med fed skrift).

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å rettelsen er ret enkel. Udfør kun de to FOR-løkker, hvis NPRIV ikke er nul.


  1. Opret et SQL Server Agent Job ved hjælp af SSMS

  2. Opret tabel ved hjælp af datostemplet

  3. Sådan filtreres objekter i SQL Server Management Studio (SSMS) - SQL Server / TSQL vejledning del 19

  4. Migrering af din adgangsdatabase til SQL Server