我已经尽力做到了这一点,但我没有在哪里。这是我的触发器定义:
CREATE OR REPLACE TRIGGER KK_BUDGET_TYPE_TR AFTER
INSERT OR
UPDATE OR
DELETE ON PS_KK_BUDGET_TYPE FOR EACH ROW DECLARE V_AUDIT_OPRID VARCHAR2(64);
V_JOB_NUMBER NUMBER;
BEGIN
DBMS_APPLICATION_INFO.READ_CLIENT_INFO(V_AUDIT_OPRID);
IF INSERTING THEN
INSERT
INTO PS_KK_BD_TYPE_AUD VALUES
(
GET_PS_OPRID(V_AUDIT_OPRID),
SYSDATE,
'A',
:NEW.SETID1,
:NEW.LEDGER_GROUP,
:NEW.EFFDT,
:NEW.EFF_STATUS,
:NEW.CNTRL_OPTN,
:NEW.BUDGET_STATUS,
:NEW.DESCR,
:NEW.BUDG_TYPE,
:NEW.ASSOC_EXP_BD,
:NEW.PARENT_BUDGET,
:NEW.CHILD_EXCEED,
:NEW.CONTROL_CHARTFIELD,
:NEW.ALL_VALUES,
:NEW.FILTER_CHARTFIELD,
:NEW.TREE_NAME,
:NEW.TREE_LEVEL,
:NEW.ENABLE_FS,
:NEW.KK_REV_TRACK_LG,
:NEW.TOLERANCE,
:NEW.BALANCED_LINES,
:NEW.KK_ENABLE_STAT,
:NEW.SUBTYPE,
:NEW.EXPIRE_CHARTFIELD
);
ELSE
IF DELETING THEN
INSERT
INTO PS_KK_BD_TYPE_AUD VALUES
(
GET_PS_OPRID(V_AUDIT_OPRID),
SYSDATE,
'D',
:OLD.SETID1,
:OLD.LEDGER_GROUP,
:OLD.EFFDT,
:OLD.EFF_STATUS,
:OLD.CNTRL_OPTN,
:OLD.BUDGET_STATUS,
:OLD.DESCR,
:OLD.BUDG_TYPE,
:OLD.ASSOC_EXP_BD,
:OLD.PARENT_BUDGET,
:OLD.CHILD_EXCEED,
:OLD.CONTROL_CHARTFIELD,
:OLD.ALL_VALUES,
:OLD.FILTER_CHARTFIELD,
:OLD.TREE_NAME,
:OLD.TREE_LEVEL,
:OLD.ENABLE_FS,
:OLD.KK_REV_TRACK_LG,
:OLD.TOLERANCE,
:OLD.BALANCED_LINES,
:OLD.KK_ENABLE_STAT,
:OLD.SUBTYPE,
:OLD.EXPIRE_CHARTFIELD
);
ELSE
INSERT
INTO PS_KK_BD_TYPE_AUD VALUES
(
GET_PS_OPRID(V_AUDIT_OPRID),
SYSDATE,
'K',
:OLD.SETID1,
:OLD.LEDGER_GROUP,
:OLD.EFFDT,
:OLD.EFF_STATUS,
:OLD.CNTRL_OPTN,
:OLD.BUDGET_STATUS,
:OLD.DESCR,
:OLD.BUDG_TYPE,
:OLD.ASSOC_EXP_BD,
:OLD.PARENT_BUDGET,
:OLD.CHILD_EXCEED,
:OLD.CONTROL_CHARTFIELD,
:OLD.ALL_VALUES,
:OLD.FILTER_CHARTFIELD,
:OLD.TREE_NAME,
:OLD.TREE_LEVEL,
:OLD.ENABLE_FS,
:OLD.KK_REV_TRACK_LG,
:OLD.TOLERANCE,
:OLD.BALANCED_LINES,
:OLD.KK_ENABLE_STAT,
:OLD.SUBTYPE,
:OLD.EXPIRE_CHARTFIELD
);
INSERT
INTO PS_KK_BD_TYPE_AUD VALUES
(
GET_PS_OPRID(V_AUDIT_OPRID),
SYSDATE,
'N',
:NEW.SETID1,
:NEW.LEDGER_GROUP,
:NEW.EFFDT,
:NEW.EFF_STATUS,
:NEW.CNTRL_OPTN,
:NEW.BUDGET_STATUS,
:NEW.DESCR,
:NEW.BUDG_TYPE,
:NEW.ASSOC_EXP_BD,
:NEW.PARENT_BUDGET,
:NEW.CHILD_EXCEED,
:NEW.CONTROL_CHARTFIELD,
:NEW.ALL_VALUES,
:NEW.FILTER_CHARTFIELD,
:NEW.TREE_NAME,
:NEW.TREE_LEVEL,
:NEW.ENABLE_FS,
:NEW.KK_REV_TRACK_LG,
:NEW.TOLERANCE,
:NEW.BALANCED_LINES,
:NEW.KK_ENABLE_STAT,
:NEW.SUBTYPE,
:NEW.EXPIRE_CHARTFIELD
);
END IF;
END IF;
DBMS_JOB.submit
(
job => V_JOB_NUMBER, what => 'logger "KK_BD_TYPE_AUD_CHG"', next_date => SYSDATE
)
;
END KK_BUDGET_TYPE_TR;
所有“这是一个可怕的想法,因为提交问题”除了,这正是我们想要发生的事情,即使发生回滚等等。某些代码正在更新某些用户不应该能够的表更新。我们完全无法确定用户在做什么,因此我们可以复制问题,因此我们当前的目标是立即通知特定表上的数据已更改,这样我们就可以立即联系用户以查找他们当时在做什么。系统管理员想要在syslog上放置一个过滤器,所以他希望我使用以下行运行命令行
logger "KK_BD_TYPE_AUD_CHG"
结果是
ORA-06550: line 1, column 100:
PLS-00103: Encountered the symbol "KK_BD_TYPE_AUD_CHG" when expecting one of the following:
:= . ( @ % ;
The symbol "; was inserted before "KK_BD_TYPE_AUD_CHG" to continue.
所以在这一点上我感到茫然,我不在我的元素之内。任何帮助或替代选项都将不胜感激。
答案 0 :(得分:0)
由于logger
是操作系统可执行文件,因此无法直接从PL / SQL调用它,因此无法直接从dbms_job
调用它。
您可以创建一个Java存储过程,该过程将使用Java操作系统API调用操作系统,将该Java存储过程的适当权限授予Oracle所有者,在Java存储过程上创建PL / SQL包装器,然后从dbms_job
调用该PL / SQL包装器。这将是相当数量的移动件,但在网上有多个这样做的例子。这个askTom question on a Java stored procedure that calls out to the host operating system可能是最好的例子。但请注意,如果您允许调用者通过任意调用,则攻击者可以使用它来运行他们想要的任何操作系统命令,因为操作系统用户在主机操作系统上运行Oracle数据库。这将允许能够调用您的程序的攻击者基本上做他们想要的任何事情或数据库,这是一个严重的安全问题。
使用dbms_scheduler
而不是dbms_job
呼叫主机操作系统的移动部件数量会减少 - 这是creating and calling an executable program from dbms_scheduler的示例。但是您无法在触发器中创建dbms_scheduler
日志,因为这样做需要隐式提交。您可以通过将触发器声明为自治事务来解决此问题。通常情况下,这不是一个选项,但由于听起来你不关心在回滚交易时收到警报,这对你来说可能是一个合理的选择。