如何找出更新表的包/程序?

N2E*_*2EE 6 plsql

我想知道是否有可能找出包中的哪个包或过程正在更新表?

由于某个项目被移交(移交项目的人已经离开)没有适当的文档,我们知道我们更新的数据总是回到一些奇怪的源点.

我们猜测这可能是在我们不知情的情况下运行update命令的数据库作业或调度程序.我希望有一种方法可以找出源代码调用的位置,即更新表并将源作为触发器插入到我们正在监视的表中.

有任何想法吗?

谢谢.

Ste*_*erg 7

更新:我探讨了如何将一个语句追溯到它自己的PL/SQL对象.

结合Tony提到的内容,您可以创建一个记录表和一个如下所示的触发器:

CREATE TABLE statement_tracker
( SID NUMBER
, serial# NUMBER
, date_run DATE
, program VARCHAR2(48) null
, module VARCHAR2(48) null
, machine VARCHAR2(64) null
, osuser VARCHAR2(30) null
, sql_text CLOB null
, program_id number
);

CREATE OR REPLACE TRIGGER smb_t_t
   AFTER UPDATE
   ON smb_test
BEGIN
   INSERT 
     INTO statement_tracker
   SELECT ss.SID
        , ss.serial#
        , sysdate
        , ss.program
        , ss.module
        , ss.machine
        , ss.osuser
        , sq.sql_fulltext
        , sq.program_id
     FROM v$session ss
        , v$sql sq
    WHERE ss.sql_address = sq.address
      AND ss.SID = USERENV('sid');
END;
/
Run Code Online (Sandbox Code Playgroud)

为了使上面的触发器能够编译,当您以SYS用户身份登录时,您需要向触发器的所有者授予这些权限:

grant select on V_$SESSION to <user>;
grant select on V_$SQL to <user>;
Run Code Online (Sandbox Code Playgroud)

您可能希望保护触发器中的insert语句,只有在您感兴趣的更改发生时才会使其记录 - 在我的测试服务器上,此语句运行得相当慢(1秒),所以我不会我想记录所有这些更新.当然,在这种情况下,您需要将触发器更改为行级触发器,以便您可以检查:new或:old值.如果您真的担心select的开销,可以将其更改为不加入v $ sql,而只是保存SQL_ADDRESS列,然后使用DBMS_JOB计划作业,并通过第二次更新更新sql_text列语句,从而将更新卸载到另一个会话,而不是阻止您的原始更新.

不幸的是,这只会告诉你一半的故事.您将要查看的语句将是最近端的语句 - 在这种情况下是更新 - 即使由启动它的进程执行的原始语句是存储过程.这是program_id列的用武之地.如果update语句是过程或触发器的一部分,program_id将指向相关代码的object_id - 您可以这样解决它:

SELECT * FROM all_objects where object_id = <program_id>;
Run Code Online (Sandbox Code Playgroud)

在直接从客户端执行update语句的情况下,我不知道program_id代表什么,但你不需要它 - 你在statement_tracker的"program"列中有可执行文件的名称.如果更新是从匿名PL/SQL块执行的,我不是如何追踪它 - 你需要进一步试验.

但是,osuser /机器/程序/模块信息可能足以让您指向正确的方向.