Oracle:是否可以在触发器中创建角色?

时间:2013-12-22 21:38:31

标签: oracle plsql triggers ddl

我有一个包含一些数据的单独表格,我希望每次在该表格中插入新行时创建一个新角色。

我创建了以下触发器:

create or replace 
TRIGGER TestTrigger
BEFORE INSERT ON TestTable
REFERENCING OLD AS OLD NEW AS NEW 

FOR EACH ROW BEGIN 
    create role :New.RoleName;
END;

但触发器无法编译。 我有错误:PLS-00103:PLS-00103:当遇到以下情况之一时遇到符号“CREATE”:(如果循环mod为空pragma提升返回选择更新,则使用<<继续关闭,开始情况声明退出goto current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge

这可能吗?

1 个答案:

答案 0 :(得分:4)

我们不能以任何形式的PL / SQL本地执行DDL。包括触发器。为此,我们需要使用动态SQL。

触发器有一个额外的皱纹:它们作为事务的一部分被触发,并且它们有一个限制,禁止我们在其体内发出提交。在Oracle中,任何DDL命令都会发出两个提交,一个在执行DDL语句之前,一个在执行之后。因此,要在触发器中执行DDL,我们必须使用autonomous_transaction pragma,这意味着DDL在单独的嵌套事务中运行。

create or replace TRIGGER TestTrigger
    BEFORE INSERT ON TestTable
    REFERENCING OLD AS OLD NEW AS NEW 
FOR EACH ROW 
declare
    pragma autonomous_transaction;
BEGIN 
    execute immediate 'create role '|| :New.RoleName;
END;

自主交易是我们容易滥用和破坏我们自己的应用程序的结构之一。在你的场景中,障碍是CREATE ROLE可以在其事务泡沫中成功,而INSERTT进入TestTable失败;这就是“自主交易”的含义。所以你仍然不能保证“[你的]表和oracle角色之间的一致性”。

更好的解决方案是将两个语句都包含在一个程序调用中,而不是试图欺骗DML做一些它不应该做的事情。

create or replace procedure create_role
     ( p_role_name in user_roles.role%type
       , p_desc in testtable.description%type )
is
    pragma autonomous_transaction;
begin 
    insert into testtable
        ( id, creationdate, rolename, description) 
    values
        ( some_seq.nextval, sysdate, p_role_name, p_desc );
    execute immediate 'create role '|| p_role_name;
end;