1

I want to do something that's conceptually simple but seems to be a lot more complex in reality.

Basically, whenever a new table is created for a couple of users in our database, I want to grant select permissions to a role. Basically this:

grant select on TABLENAME to READROLE;

So far my trigger looks something like this:

CREATE OR REPLACE TRIGGER osmm_grant_on_creation

AFTER CREATE ON OSMM.SCHEMA

BEGIN

    //grant goes here

END

Problem is, I can't figure out how to join the two together by getting the name of the newly created table and referencing it through the trigger to the grant. Any suggestions? Thanks.

4

2 回答 2

13

它可能比你想象的更复杂。该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
于 2012-02-13T15:38:43.650 回答
-1

您可能需要执行以下操作:

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

但我无法检查它是否有效

于 2012-02-13T15:37:57.670 回答