Как создать триггер Oracle, предоставляющий разрешения

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

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

grant select on TABLENAME to READROLE;

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

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

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

НАЧИНАТЬ

    //grant goes here

КОНЕЦ

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


person Community    schedule 13.02.2012    source источник
comment
Какие-либо предложения? Конечно: не делай этого. Предоставленные разрешения являются частью конфигурации нашей базы данных. Таким образом, они должны быть написаны сценариями и храниться в репозитории системы управления версиями вместе с DDL для создания таблицы.   -  person APC    schedule 13.02.2012
comment
@APC - Почему я не хочу этого делать? Я не являюсь администратором баз данных и имею ограниченные знания Oracle, поэтому боюсь, что ваш ответ не имеет смысла. Есть ли другой способ автоматически предоставить разрешения на выбор роли для новой таблицы? Потому что делать это вручную — это рутинная работа, которую мы хотели бы избежать. Триггеры кажутся очевидным решением, но если есть лучший способ, я открыт для него.   -  person    schedule 13.02.2012
comment
Триггеры — это единственный способ автоматически предоставлять разрешения на объекты по запросу, и это непросто (как показывает ответ Джастина). Это сложно, потому что не требуется предоставлять одни и те же разрешения на все таблицы в схеме кому-то еще (роль или пользователь). Более распространено предоставление различных привилегий для подмножества таблиц, часто для разных учетных записей. Это сложная логика для запуска триггера. Более распространенный подход (кроме кода вырезания и вставки) заключается в использовании метаданных для создания сценариев.   -  person APC    schedule 14.02.2012
comment
Я подозреваю, что это не то, на что вы надеялись. Это вопрос лучшего определения. Лучше может означать меньше ввода, но это также может означать более надежную, более гибкую, более отслеживаемую.   -  person APC    schedule 14.02.2012
comment
@ACL - Спасибо за разъяснение. Исходя из нашего варианта использования, по-прежнему кажется, что это лучший способ для нас. У нас есть более 1000 таблиц для этих двух пользователей, которым нужны одинаковые разрешения. Новые таблицы создаются способом, который не позволяет нам легко предоставлять привилегии, поэтому вместо того, чтобы продолжать делать это вручную, это кажется оптимальным. Спасибо за отзыв.   -  person    schedule 14.02.2012


Ответы (2)


Вероятно, это сложнее, чем вы даже думаете. Оператор 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
person Justin Cave    schedule 13.02.2012
comment
+1 за то, что сказал не делать этого, затем -1 за то, что показал им, как решить проблемы. - person APC; 13.02.2012
comment
@APC - к сожалению, я сделал что-то подобное, чтобы иметь дело с упакованным приложением, которое периодически создавало новые таблицы, и в этом случае триггер был разумным обходным путем (учитывая, что замена системы не была стартовой). Но это следует признать массовым взломом. - person Justin Cave; 13.02.2012
comment
Согласно информации, которую я нашел, некоторые DDL разрешены в триггерах уровня схемы (что неясно). - person Allan; 13.02.2012
comment
@Allan - Нет. DDL не разрешен в триггерах на уровне схемы. Обновлен мой ответ с ошибкой, которую вы получите, если попытаетесь. - person Justin Cave; 13.02.2012
comment
Справедливое замечание Джастин. Я предполагаю, что цель SO состоит в том, чтобы предоставить искателям ответы, даже если иногда ответами являются заряженный пистолет. Все, что мы можем сделать, это предупредить их, что они могут пустить пыль в глаза. Итак, +1 - person APC; 13.02.2012
comment
@JustinCave: от Oracle: DDL, разрешенный внутри этих триггеров, — это изменение, создание или удаление таблицы, создание триггера и операции компиляции. Это конкретно связано с триггерами входа и выхода, поэтому это могут быть только те, которые разрешают DDL, но это несколько неясно. В любом случае очевидно, что некоторые DDL разрешены некоторыми системными триггерами, но не этим DDL (и, возможно, не в этом системном триггере). - person Allan; 13.02.2012
comment
@JustinCave - спасибо за ответ. Я предположу, что это работает, и поставлю галочку. Если APC вернется с решением, которое не является заряженным пистолетом, я могу пойти по этому пути, но оставлю галочку. Всем привет. - person ; 13.02.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

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

person A.B.Cade    schedule 13.02.2012
comment
Как написано, я считаю, что это вызовет ошибку, если созданный объект не является таблицей, поскольку он попытается выполнить grant select on to READROLE. - person Allan; 13.02.2012