某些记录正在从表中删除,我们想确定从表中删除记录的sql语句,以便我们可以检查找到引起问题的程序。
我编写了以下内容,但sql
create or replace
trigger find_del_abc
before delete on abc
for each row
declare
temp_audsid integer;
temp_sql_id VARCHAR2(13);
temp_prev_sql_id VARCHAR2(13);
begin
If deleting then
select sql_id, prev_sql_id, audsid into temp_sql_id, temp_prev_sql_id, temp_audsid from v$session where audsid = SYS_CONTEXT('USERENV','sessionid');
insert into delete_abc_session
select * from v$session where audsid = temp_audsid;
insert into my_sql
select sql_id, sql_fulltext from v$sqlarea where sql_id in (temp_sql_id, temp_prev_sql_id);
End If;
end;
但是我在my_sql中看不到“从abc删除” sql。 我在做错什么吗?
还有其他方法可以捕获调用触发器的sql语句的sql_id,prev_sql_id,audsid(在触发器块内部)。
在此方面,谢谢您的帮助。
答案 0 :(得分:3)
还有其他方法可以捕获调用触发器的sql语句的sql_id,prev_sql_id,audsid(在触发器块内部)。
不容易。
好吧,AUDSID很简单:使用表达式SYS_CONTEXT('USERENV','SESSIONID')
据我所知,获取SQL_ID是不可能的,但 可能但很难获取SQL文本。
为此,您将需要在表上创建细粒度审核(FGA)策略。在FGA策略处理程序中,您可以访问SYS_CONTEXT('USERENV','CURRENT_SQL')
。如果您的策略处理程序将其保存在某个地方,则触发器可以访问它。
不幸的是,您的触发器必须是AFTER触发器,因为BEFORE触发器将在FGA策略之前执行。
这是一个简单的例子:
--DROP TABLE matt1;
CREATE TABLE matt1 ( a number );
CREATE OR REPLACE PACKAGE xxcust_record_last_sql_pkg AS
-- TODO: you probably would want to store a collection of last SQL by table name
l_last_sql VARCHAR2(32000);
PROCEDURE record_last_sql (object_schema VARCHAR2, object_name VARCHAR2, policy_name VARCHAR2);
FUNCTION get_last_sql RETURN VARCHAR2;
END xxcust_record_last_sql_pkg;
/
CREATE OR REPLACE PACKAGE BODY xxcust_record_last_sql_pkg AS
PROCEDURE record_last_sql (object_schema VARCHAR2, object_name VARCHAR2, policy_name VARCHAR2) IS
BEGIN
xxcust_record_last_sql_pkg.l_last_sql := SUBSTR(SYS_CONTEXT ('userenv', 'CURRENT_SQL'),1,32000);
-- raise_application_error(-20001,'SQL = ' || xxcust_record_last_sql_pkg.l_last_sql);
END record_last_sql;
FUNCTION get_last_sql RETURN VARCHAR2 IS
BEGIN
RETURN xxcust_record_last_sql_pkg.l_last_sql;
END get_last_sql;
END xxcust_record_last_sql_pkg;
/
--EXEC DBMS_FGA.drop_policy (user, 'MATT1', 'MATT_TEST_POLICY');
BEGIN
DBMS_FGA.add_policy (
object_schema => user,
object_name => 'MATT1',
policy_name => 'MATT_TEST_POLICY',
audit_condition => '1=1',
audit_column => null,
handler_schema => user,
handler_module => 'XXCUST_RECORD_LAST_SQL_PKG.RECORD_LAST_SQL',
statement_Types => 'INSERT,UPDATE,DELETE',
enable => TRUE);
END;
/
--drop trigger matt1_ari1;
create or replace trigger matt1_ari1 after insert on matt1 for each row
begin
raise_application_error(-20001, 'Invoking SQL was: ' || substr(xxcust_record_last_sql_pkg.get_last_sql,1,4000));
end;
/
insert into matt1 (a) select 7*rownum from dual connect by rownum <= 5;
Error starting at line : 54 in command - insert into matt1 (a) select 7*rownum from dual connect by rownum <= 5 Error report - ORA-20001: Invoking SQL was: insert into matt1 (a) select 7*rownum from dual connect by rownum <= 5 ORA-06512: at "APPS.MATT1_ARI1", line 4 ORA-04088: error during execution of trigger 'APPS.MATT1_ARI1'
我假设您有这样做的正当理由。很难做到这一点的一个原因是,没有通用的用例。有审计和安全性来控制对表的访问。实际上,我敢打赌,适当地单独使用细粒度的审核功能(即在表上没有自定义触发器)将是一种更好的方式来完成您想做的事情。