首页 文章

Oracle 'after create'触发器授予权限

提问于
浏览
0

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

如果我执行一个 create table ... as select 语句然后在TOAD中的同一代码块或不同的UI中查询新表我遇到错误,但是如果我单独运行命令它会起作用:

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

select count(*) from schema1.table1;

如果我将它们作为一个代码块执行,我得到:

ORA-01031: insufficient privileges

如果我单独执行它们,我不会收到错误并且能够获得正确的计数 .

AFTER CREATE触发器的示例片段

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;

1 回答

  • 2

    工作是异步的 . 你的代码不是 .

    暂时忽略这样一个事实,即如果你动态授予世界上某些东西正在创建新表格的权限,而不需要经过变更控制流程(此时人类审稿人会确保包含适当的授权),这意味着你有一个更大的问题......

    运行 CREATE TABLE 语句时,将触发触发器并计划运行作业 . 该作业在单独的会话中运行,并且在 CREATE TABLE 语句发出其最终隐式提交并将控制权返回给第一个会话之前无法启动 . 最好的情况是,该作业在 CREATE TABLE 语句完成后运行一两秒钟 . 但它可能会更长,具体取决于允许同时运行多少个后台作业,正在运行的其他作业,Oracle的繁忙程度等等 .

    最简单的方法是在 CREATE TABLESELECT 之间添加 dbms_lock.sleep 调用,等待一段合理的时间来运行后台作业时间 . 那_1035777不是万无一失的 . 即使您进行了"long enough"的延迟测试,您将来可能会遇到更长的延迟 . 更复杂的方法是查询 dba_jobs ,查看是否有与您刚创建的表相关的作业,如果存在循环则休眠 .

相关问题