Oracle 甲骨文';创建后';触发以授予特权

Oracle 甲骨文';创建后';触发以授予特权,oracle,triggers,privileges,grant,Oracle,Triggers,Privileges,Grant,我有一个'after create on database'触发器,用于为不同的Oracle角色提供对特定模式中新创建的表的select访问 如果我执行创建表。。。在select语句中,然后在TOAD中的同一代码块或不同的UI中查询新表时,我遇到了一个错误,但如果我单独运行命令,它会工作: create table schema1.table1 as select * from schema2.table2 where rownum < 2; select count(*) from s

我有一个'after create on database'触发器,用于为不同的Oracle角色提供对特定模式中新创建的表的select访问

如果我执行
创建表。。。在select
语句中,然后在TOAD中的同一代码块或不同的UI中查询新表时,我遇到了一个错误,但如果我单独运行命令,它会工作:

create table schema1.table1 as select * from schema2.table2 where rownum < 2;

select count(*) from schema1.table1;
如果我单独执行它们,我不会得到错误并且能够获得正确的计数

创建后触发器的示例代码段

 CREATE OR REPLACE TRIGGER TGR_DATABASE_AUDIT AFTER
 CREATE OR DROP OR ALTER ON Database
 DECLARE
    vOS_User              VARCHAR2(30);
    vTerminal             VARCHAR2(30);
    vMachine              VARCHAR2(30);
    vSession_User         VARCHAR2(30);
    vSession_Id           INTEGER;
    l_jobno               NUMBER;

 BEGIN

   SELECT sys_context('USERENV', 'SESSIONID'),
          sys_context('USERENV', 'OS_USER'),
          sys_context('USERENV', 'TERMINAL'),
          sys_context('USERENV', 'HOST'),
          sys_context('USERENV', 'SESSION_USER')
   INTO   vSession_Id,
          vOS_User,
          vTerminal,
          vMachine,
          vSession_User
    FROM Dual;

    insert into schema3.event_table VALUES (vSession_Id, SYSDATE,   
    vSession_User, vOS_User, vMachine, vTerminal, ora_sysevent,  
    ora_dict_obj_type,ora_dict_obj_owner,ora_dict_obj_name);

    IF ora_sysevent = 'CREATE' THEN
       IF (ora_dict_obj_owner = 'SCHEMA1')  THEN
           IF DICTIONARY_OBJ_TYPE = 'TABLE' THEN
              dbms_job.submit(l_jobno,'sys.execute_app_ddl(''GRANT SELECT 
              ON '||ora_dict_obj_owner||'.'||ora_dict_obj_name||' TO 
              Role1,Role2'');');
           END IF;
       END IF;
    END IF;
 END;

作业是异步的。您的代码不正确

暂时忽略这样一个事实,即如果您动态授予特权,即世界上有一些东西正在生产中创建新表,而没有经过更改控制过程(此时,人工审阅者将确保包括适当的授予),这意味着您有一个更大的问题

当您运行
createtable
语句时,将触发触发器并计划运行作业。该作业在单独的会话中运行,只有在
CREATE TABLE
语句发出其最终隐式提交并将控制权返回到第一个会话后才能启动。最好的情况是,该作业在
createtable
语句完成后运行一两秒钟。但时间可能会更长,这取决于允许同时运行多少后台作业、正在运行哪些其他作业、Oracle有多忙等等


最简单的方法是在
CREATE TABLE
SELECT
之间添加一个
dbms\u lock.sleep
调用,该调用等待一段合理的时间来给后台作业运行时间。这对于编写代码来说是微不足道的(并且有助于验证这实际上是您唯一的问题),但它不是万无一失的。即使您为测试设置了“足够长”的延迟,您将来也可能会遇到更长的延迟。更复杂的方法是查询
dba_作业
,查看是否有与刚才创建的表相关的作业,如果有循环,则休眠。

好吧,您必须给提交的作业一段时间才能完成,是吗?你的问题是什么?为什么它会出错,或者如何阻止它出错?您是否需要在触发器中使用作业,而不仅仅是动态SQL?(无论如何,在运行时创建表似乎是一个坏主意,但这并不是真正相关的…)为了回答我自己的部分问题,是的,您确实需要使用作业,当然-您不能使用
executeimmediate
来运行grant DDL,因为您不能在触发器中提交。。。这大概就是为什么您首先要异步执行此操作的原因。
 CREATE OR REPLACE TRIGGER TGR_DATABASE_AUDIT AFTER
 CREATE OR DROP OR ALTER ON Database
 DECLARE
    vOS_User              VARCHAR2(30);
    vTerminal             VARCHAR2(30);
    vMachine              VARCHAR2(30);
    vSession_User         VARCHAR2(30);
    vSession_Id           INTEGER;
    l_jobno               NUMBER;

 BEGIN

   SELECT sys_context('USERENV', 'SESSIONID'),
          sys_context('USERENV', 'OS_USER'),
          sys_context('USERENV', 'TERMINAL'),
          sys_context('USERENV', 'HOST'),
          sys_context('USERENV', 'SESSION_USER')
   INTO   vSession_Id,
          vOS_User,
          vTerminal,
          vMachine,
          vSession_User
    FROM Dual;

    insert into schema3.event_table VALUES (vSession_Id, SYSDATE,   
    vSession_User, vOS_User, vMachine, vTerminal, ora_sysevent,  
    ora_dict_obj_type,ora_dict_obj_owner,ora_dict_obj_name);

    IF ora_sysevent = 'CREATE' THEN
       IF (ora_dict_obj_owner = 'SCHEMA1')  THEN
           IF DICTIONARY_OBJ_TYPE = 'TABLE' THEN
              dbms_job.submit(l_jobno,'sys.execute_app_ddl(''GRANT SELECT 
              ON '||ora_dict_obj_owner||'.'||ora_dict_obj_name||' TO 
              Role1,Role2'');');
           END IF;
       END IF;
    END IF;
 END;