Oracle 甲骨文';创建后';触发以授予特权
我有一个'after create on database'触发器,用于为不同的Oracle角色提供对特定模式中新创建的表的select访问 如果我执行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
创建表。。。在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;