我有一个'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 回答
工作是异步的 . 你的代码不是 .
暂时忽略这样一个事实,即如果你动态授予世界上某些东西正在创建新表格的权限,而不需要经过变更控制流程(此时人类审稿人会确保包含适当的授权),这意味着你有一个更大的问题......
运行
CREATE TABLE
语句时,将触发触发器并计划运行作业 . 该作业在单独的会话中运行,并且在CREATE TABLE
语句发出其最终隐式提交并将控制权返回给第一个会话之前无法启动 . 最好的情况是,该作业在CREATE TABLE
语句完成后运行一两秒钟 . 但它可能会更长,具体取决于允许同时运行多少个后台作业,正在运行的其他作业,Oracle的繁忙程度等等 .最简单的方法是在
CREATE TABLE
和SELECT
之间添加dbms_lock.sleep
调用,等待一段合理的时间来运行后台作业时间 . 那_1035777不是万无一失的 . 即使您进行了"long enough"的延迟测试,您将来可能会遇到更长的延迟 . 更复杂的方法是查询dba_jobs
,查看是否有与您刚创建的表相关的作业,如果存在循环则休眠 .