Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

ORA-6502 với Trình kích hoạt ghi nhật ký cấp

Tôi có một dự án mới, tôi đang làm việc mà tôi muốn có một công việc Oracle, thu hồi các đặc quyền mà tôi đã cấp cho nhân viên CNTT trên 30 ngày. Nhân viên CNTT của chúng tôi thỉnh thoảng cần truy cập vào một số bàn sản xuất để khắc phục sự cố. Chúng tôi cấp quyền ưu tiên CHỌN trên các bàn mà người đó cần, nhưng không ai nói với tôi khi nào họ hoàn thành nhiệm vụ của mình và những đặc quyền đó sẽ mãi mãi ở đó. Tôi muốn hệ thống tự động thu hồi các đặc quyền cũ hơn 30 ngày để tôi không phải nhớ làm điều đó. Trước khi tôi có thể thu hồi các đặc quyền, tôi cần một cách để theo dõi các đặc quyền đó. Vì vậy, tôi đã tạo một trình kích hoạt được kích hoạt bất cứ khi nào GRANT được cấp và ghi lại các chi tiết vào một bảng. Sau đó, một công việc của Oracle sẽ quét bảng đó và thu hồi các đặc quyền mà nó phát hiện là quá cũ. Mã kích hoạt của tôi như sau:

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

Mã trên không phải là mã gốc. Tôi đã tìm thấy một ví dụ điển hình trên Internet và đã sửa đổi một vài điều. Sau khi kiểm tra mã trong 3 tuần, tôi đã đưa bộ kích hoạt vào sản xuất. Tôi chỉ mất vài ngày để nhận lỗi.

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… Tôi đang tạo một người dùng không cấp bất kỳ thứ gì. Nhưng chúng tôi chắc chắn có thể thấy trình kích hoạt của tôi đang gặp sự cố khi thực thi. Vậy tại sao trình kích hoạt này lại kích hoạt nếu tất cả những gì tôi đang làm là tạo người dùng? Một dấu vết SQL đơn giản đã cho tôi thấy điều gì đang xảy ra với SQL đệ quy đó. Đằng sau hậu trường, Oracle đang thay mặt tôi phát hành những điều sau:

CẤP QUYỀN RIÊNG TƯ INHERIT TRÊN NGƯỜI DÙNG “BOB” thành CÔNG;

Được rồi… vậy tại thời điểm này, tôi biết rằng có một GRANT được cấp khi tôi tạo người dùng nhưng tại sao điều này không thành công? Tôi đã thử nghiệm trình kích hoạt này với các đặc quyền của hệ thống và nó hoạt động tốt. Đúng là, tôi đã không kiểm tra CÁC QUYỀN RIÊNG TƯ CỦA INHERIT, vì vậy đây là một loại trường hợp lợi hại.

Sau rất nhiều nỗ lực gỡ lỗi, tôi xác định rằng lệnh gọi hàm ora_privilege_list đang trả về một tập hợp trống cho tập hợp có tên “priv”. Như vậy, npriv đang được đặt thành giá trị NULL. Bởi vì NPRIV là NULL, dòng có nội dung "cho tôi trong 1..npriv" không có ý nghĩa nhiều, do đó lỗi.

Theo ý kiến ​​của tôi, ora_privilege_list nên trả về một mục, “INHERIT PRIVILEGES” và tôi tin rằng nó không trả về danh sách đó là một lỗi. Tuy nhiên, nếu ora_privilege_list sẽ trả về một tập hợp rỗng, thì kết quả đầu ra từ hàm phải bằng 0 và sau đó npriv sẽ nhận một giá trị thích hợp hơn. Đối với mục đích giáo dục, ora_privilege_list là một từ đồng nghĩa với DBMS_STANDARD.PRIVILEGE_LIST.

Tất cả những gì đang được nói, tôi không thể kiểm soát chức năng Oracle. Và tôi không muốn đợi Oracle thay đổi mã của họ trong DBMS_STANDARD về những gì tôi nghĩ phải như vậy. Vì vậy, tôi sẽ chỉ viết mã trình kích hoạt của mình để xử lý vấn đề. Thêm hai dòng đơn giản đã giải quyết được vấn đề của tôi (được in đậm bên dưới).

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

Vì vậy, cách khắc phục khá đơn giản. Chỉ thực hiện hai vòng lặp FOR nếu NPRIV không rỗng.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chuỗi cập nhật trong Oracle với mili giây

  2. Sự cố tò mò với Oracle UNION và ORDER BY

  3. Triển khai Khóa lạc quan trong Oracle

  4. Bảng bên ngoài Oracle

  5. CHÈN và CẬP NHẬT bản ghi bằng cách sử dụng con trỏ trong oracle