我在数据库创建后有一个''触发器为特定模式中新创建的表提供对不同Oracle角色的选择访问。
如果我执行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;
答案 0 :(得分:2)
乔布斯是异步的。你的代码不是。
暂时忽略这样一个事实:如果您动态授予特权,即世界上的某些东西正在创建新表,而不需要通过变更控制流程(此时人工审核人员会确保适当的授权)包括在内)这意味着你有一个更大的问题......
运行CREATE TABLE
语句时,将触发触发器并计划运行作业。该作业在单独的会话中运行,并且无法启动,直到您的CREATE TABLE
语句发出其最终的隐式提交并将控制权返回给第一个会话。最好的情况是,该作业在CREATE TABLE
语句完成后运行一两秒。但它可能会更长,具体取决于允许同时运行多少个后台作业,正在运行的其他作业,Oracle的繁忙程度等等。
最简单的方法是在dbms_lock.sleep
和CREATE TABLE
之间添加一个SELECT
调用,等待一段合理的时间来运行后台作业。编写代码是微不足道的(并且有助于验证这实际上是您遇到的唯一问题),但它并非万无一失。即使你拖延了足够长的时间&#34;对于测试,您将来可能会遇到更长的延迟。更复杂的方法是查询dba_jobs
,查看是否有与您刚创建的表相关的作业,如果存在循环则休眠。