Как создать триггер Oracle, который предоставляет разрешения - PullRequest
1 голос
/ 13 февраля 2012

Я хочу сделать что-то, что концептуально просто, но кажется намного сложнее в реальности.

По сути, всякий раз, когда создается новая таблица для пары пользователей в нашей базе данных, я хочу предоставить права на выбор роли. В основном это:

grant select on TABLENAME to READROLE;

Пока мой триггер выглядит примерно так:

СОЗДАТЬ ИЛИ ЗАМЕНИТЬ ТРИГГЕР osmm_grant_on_creation

ПОСЛЕ СОЗДАНИЯ НА OSMM.SCHEMA

НАЧАТЬ

    //grant goes here

END

Проблема в том, что я не могу понять, как соединить их вместе, получая имя вновь созданной таблицы и ссылаясь на нее через триггер для предоставления. Какие-либо предложения? Спасибо.

Ответы [ 2 ]

12 голосов
/ 13 февраля 2012

Это, вероятно, сложнее, чем вы думаете. Оператор GRANT является DDL, что означает, что он выдает неявные коммиты, что означает, что вы не можете напрямую поместить его в триггер. Ваш триггер должен будет отправить задание, запущенное в отдельном сеансе после совершенной инициирующей транзакции, которая фактически предоставит грант. А это значит, что вам нужно использовать более старый пакет DBMS_JOB для планирования задания, поскольку более современный DBMS_SCHEDULER также неявно фиксирует коммит.

Поскольку в Oracle вам не нужно создавать таблицы «на лету», правильное место для такого рода грантов - скрипты сборки, которые вы запускаете для создания таблицы. Полагаясь на триггеры для выполнения таких вещей, как гранты, только усложняется правильное построение, потому что выполнение одного и того же сценария в двух разных средах может привести к двум разным результатам из-за различий в триггере.

Однако, если вы полны решимости пойти по этому пути, вы, вероятно, захотите что-то вроде

Процедура, которая предоставляет привилегию

CREATE OR REPLACE PROCEDURE grant_select_to_readrole( p_table_name IN VARCHAR2 )
AS
BEGIN
  EXECUTE IMMEDIATE 'grant select on ' || p_table_name || ' to readrole';
END;

И триггер, который отправляет задание, которое вызывает эту процедуру

CREATE OR REPLACE TRIGGER osmm_grant_on_creation
  AFTER CREATE ON OSMM.SCHEMA
AS
  l_jobno PLS_INTEGER;
BEGIN
  dbms_job.submit( l_jobno,
                   'BEGIN grant_select_to_readrole( ''' || ora_dict_obj_name || ''' ); END;',
                   sysdate + interval '10' second );
END;

Если вы попытаетесь выполнить DDL в самом триггере уровня схемы, вы получите ошибку

SQL> ed
Wrote file afiedt.buf

  1  create or replace trigger after_create_on_scott
  2    after create on schema
  3  declare
  4  begin
  5    execute immediate 'grant select on scott.emp to hr';
  6* end;
SQL> /

Trigger created.

SQL> create table foo( col1 number );
create table foo( col1 number )
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-30511: invalid DDL operation in system triggers
ORA-06512: at line 3
0 голосов
/ 13 февраля 2012

вам, вероятно, нужно сделать что-то вроде:

CREATE OR REPLACE TRIGGER osmm_grant_on_creation

AFTER CREATE ON OSMM.SCHEMA
DECLARE
new_obj_name varchar2(30);
BEGIN
SELECT ora_dict_obj_name
INTO new_obj_name
FROM dual
WHERE ora_dict_obj_type = 'TABLE';

execute immediate 'grant select on ' || new_obj_name || ' to READROLE';
END

, но я не могу проверить, работает ли он

...