为啥在 raise_application_error 未执行之前的触发器内部代码?
Posted
技术标签:
【中文标题】为啥在 raise_application_error 未执行之前的触发器内部代码?【英文标题】:Why inside of a trigger the code before raise_application_error isn't executed?为什么在 raise_application_error 未执行之前的触发器内部代码? 【发布时间】:2018-04-26 20:42:46 【问题描述】:如果我创建了这个触发器,那么当对表使用 drop 或 truncate 时会引发错误,但 logTable 中没有插入任何内容,但是如果我删除 RAISE_APPLICATION_ERROR... 那么值将插入 logTable,但 drop /truncate 也被执行。为什么?如何避免在 Schema 上删除/截断(如果我使用而不是触发器,则仅当架构的所有者正在删除/截断某些内容时才会触发它)。
CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
IF ora_dict_obj_owner = 'MySchema' THEN
select user INTO username from dual;
INSERT INTO logTable VALUES(username , SYSDATE);
RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
END IF;
END;
【问题讨论】:
出于兴趣,select user INTO username from dual
的目的是什么?
目的是将想要从 MySchema 中删除/截断表的用户名添加到日志表中。
但你已经知道user
。该查询似乎只是将其复制到名称略有不同的变量中。现在username
与user
具有相同的值。它似乎没有给你任何你不知道的东西。
如果我有,例如,两个用户可以访问相同的模式并且有人试图删除一个表,那么在日志表中我有用户名和他试图删除表的时间.
但你不能只是insert into logTable values (user, sysdate)
?必须有第二个变量和一个查询来填充它?
【参考方案1】:
根据documentation:
语句级原子性
Oracle 数据库支持语句级原子性,这意味着 SQL 语句是一个原子工作单元 要么完全成功,要么完全失败。
成功的语句不同于已提交的事务。一种 如果数据库解析并成功执行单个 SQL 语句 作为一个原子单元运行它而不会出错,就像所有行都更改时一样 在多行更新中。
如果 SQL 语句在执行过程中导致错误,那么它不是 成功,因此该语句的所有效果都将回滚。这 操作是语句级回滚。
该过程是一个 PL/SQL 语句,它是原子的,如果您在该过程中引发错误,那么整个过程将失败,Oracle 会对该过程所做的所有更改执行回滚。
但是您可以使用AUTONOMOUS_TRANSACTION Pragma 创建一个过程以绕过此行为,方式如下:
CREATE TABLE logtable(
username varchar2(200),
log_date date
);
CREATE OR REPLACE PROCEDURE log_message( username varchar2 ) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO logtable( username, log_date ) VALUES ( username, sysdate );
COMMIT;
END;
/
CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
IF ora_dict_obj_owner = 'TEST' THEN
log_message( user );
RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
END IF;
END;
现在:
drop table table1;
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: ERROR, YOU CAN NOT DELETE THIS!!
ORA-06512: at line 6
00604. 00000 - "error occurred at recursive SQL level %s"
*Cause: An error occurred while processing a recursive SQL statement
(a statement applying to internal dictionary tables).
*Action: If the situation described in the next error on the stack
can be corrected, do so; otherwise contact Oracle Support.
select * from logtable;
USERNAME LOG_DATE
-------- -------------------
TEST 2018-04-27 00:16:34
【讨论】:
以上是关于为啥在 raise_application_error 未执行之前的触发器内部代码?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 CoreGui Roblox 锁定在 DataModel 中,为啥受信任的用户不能使用 CoreScripts?
为啥 + 仅在客户端是 NaN?为啥不在 Node.js 中?
为啥我们不能在 TypeScript 类中定义一个 const 字段,为啥静态只读不起作用?