如何创建授予权限的Oracle触发器

如何创建授予权限的Oracle触发器,oracle,triggers,ddl-trigger,Oracle,Triggers,Ddl Trigger,我想做一些概念上简单,但实际上似乎复杂得多的事情 基本上,每当为数据库中的两个用户创建一个新表时,我都希望向角色授予select权限。基本上: 将TABLENAME上的select授予READROLE 到目前为止,我的触发器看起来像这样: 在创建时创建或替换触发器osmm\U grant\U 在OSMM.SCHEMA上创建后 开始 结束 问题是,我不知道如何通过获取新创建表的名称并通过触发器将其引用到grant来将两者连接在一起。 有什么建议吗?谢谢。您可能需要执行以下操作: CREATE OR

我想做一些概念上简单,但实际上似乎复杂得多的事情

基本上,每当为数据库中的两个用户创建一个新表时,我都希望向角色授予select权限。基本上:

将TABLENAME上的select授予READROLE

到目前为止,我的触发器看起来像这样:

在创建时创建或替换触发器osmm\U grant\U

在OSMM.SCHEMA上创建后

开始

结束

问题是,我不知道如何通过获取新创建表的名称并通过触发器将其引用到grant来将两者连接在一起。
有什么建议吗?谢谢。

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

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

但我无法检查它是否有效

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

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

但我无法检查它是否有效,它可能比你想象的还要复杂。
GRANT
语句是DDL,这意味着它发出隐式提交,这意味着不能直接将其放入触发器中。您的触发器将需要提交一个作业,该作业在触发事务提交后在单独的会话中运行,该事务将实际执行授权。这意味着您必须使用较旧的
DBMS\u作业
包来调度作业,因为更现代的
DBMS\u调度程序也隐式提交

由于您首先不应该在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

这可能比你想象的还要复杂。
GRANT
语句是DDL,这意味着它发出隐式提交,这意味着不能直接将其放入触发器中。您的触发器将需要提交一个作业,该作业在触发事务提交后在单独的会话中运行,该事务将实际执行授权。这意味着您必须使用较旧的
DBMS\u作业
包来调度作业,因为更现代的
DBMS\u调度程序也隐式提交

由于您首先不应该在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

有什么建议吗?当然,不要这样做。授予的权限是数据库配置的一部分。因此,它们应该编写脚本并保存在源代码管理存储库中,与DDL一起用于创建表。@APC-为什么我不想这样做?我不是DBA,对Oracle的了解有限,因此我担心您的回答毫无意义。是否有其他方法可以自动为新表的角色授予select权限?因为手动操作是我们想要避免的一件琐事。触发器似乎是一个显而易见的解决方案,但如果有“更好”的方法,我愿意接受。触发器是按需自动授予对象权限的唯一方法,这并不容易(正如Justin的回答所示)。这很困难,因为需要将架构中所有表的相同权限授予其他人(角色或用户)是不常见的。在表的子集上授予各种特权更为常见,通常是授予不同的帐户。这是一个很难触发的逻辑。更常见的方法(而不是剪切粘贴编码)是使用元数据生成脚本。我想这不是您所希望的。这是定义“更好”的问题。“更好”可能意味着更少的键入,但也可能意味着更健壮、更灵活、更可跟踪。@ACL-感谢您的澄清。基于我们的用例,这似乎仍然是我们最好的方法。我们为这两个用户提供了1000多个表,所有这些表都需要相同的权限。新表的创建方式不允许我们轻松地授予priv,因此不允许我们继续手动操作,这似乎是最佳选择。谢谢你的反馈。有什么建议吗?当然,不要这样做。授予的权限是数据库配置的一部分。因此,它们应该编写脚本并保存在源代码管理存储库中,与DDL一起用于创建表。@APC-为什么我不想这样做?我不是DBA,对Oracle的了解有限,因此我担心您的回答毫无意义。是否有其他方法可以自动为新表的角色授予select权限?因为手动操作是我们想要避免的一件琐事。触发器似乎是一个显而易见的解决方案,但如果有“更好”的方法,我愿意接受。触发器是按需自动授予对象权限的唯一方法,这并不容易(正如Justin的回答所示)。这很困难,因为需要将架构中所有表的相同权限授予其他人(角色或用户)是不常见的。在ta的子集上授予各种特权更为常见