Oracle 12c在带外键的表上使用onDelete触发器和onDelete级联setNull引发ORA-00600:内部错误代码,参数:[13001]

时间:2019-09-10 16:19:32

标签: oracle foreign-keys database-trigger cascade ora-00600

蜂拥而至,这就是问题所在,如果没有StackOverflow人群的帮助,我似乎无法解决:)

给出此Oracle数据库

  • Oracle Database 12c企业版12.1.0.2.0版-64位
  • 生产PL / SQL版本12.1.0.2.0-生产
  • 用于Solaris的“ CORE 12.1.0.2.0生产” TNS:版本12.1.0.2.0-
  • 生产NLSRTL版本12.1.0.2.0-生产

此DDL和数据:

CREATE TABLE TR_TEST_HIST ( 
    AUDIT_EVENT_TIMESTAMP date  NOT NULL,
    AUDIT_EVENT_TYPE     char(1)  NOT NULL,
    ID                   number(19)  NOT NULL,
    BUSINESS_KEY         varchar2(255)  NOT NULL,
    LINKED_ID            number(19)  
 );

CREATE INDEX PK_TR_TEST_0 ON TR_TEST_HIST ( ID );

CREATE INDEX IDX_TR_TEST_0 ON TR_TEST_HIST ( LINKED_ID );

CREATE TABLE TR_TEST ( 
    ID                   number(19)  NOT NULL,
    BUSINESS_KEY         varchar2(255)  NOT NULL,
    LINKED_ID            number(19)  ,
    CONSTRAINT PK_TR_TEST PRIMARY KEY ( ID ) 
 );

CREATE INDEX IDX_TR_TEST ON TR_TEST ( LINKED_ID );

CREATE OR REPLACE TRIGGER TR_TEST_AUDIT_TRIGGER
                                BEFORE DELETE OR UPDATE ON TR_TEST
                                FOR EACH ROW
                              DECLARE
                                VAR_CHANGE_TYPE CHAR(1);
                              BEGIN
                                IF UPDATING THEN VAR_CHANGE_TYPE := 'U'; ELSE VAR_CHANGE_TYPE := 'D'; END IF;
                                INSERT INTO TR_TEST_HIST (AUDIT_EVENT_TIMESTAMP,
AUDIT_EVENT_TYPE,
BUSINESS_KEY,
ID,
LINKED_ID) VALUES (CURRENT_TIMESTAMP,
VAR_CHANGE_TYPE,
:OLD.BUSINESS_KEY,
:OLD.ID,
:OLD.LINKED_ID);
                              END TR_TEST_AUDIT_TRIGGER;

ALTER TABLE TR_TEST ADD CONSTRAINT FK_TR_TEST_LINKED FOREIGN KEY ( LINKED_ID ) REFERENCES TR_TEST( ID ) ON DELETE SET NULL;

INSERT INTO TR_TEST( ID, BUSINESS_KEY, LINKED_ID ) VALUES ( 4, 'entry_4', 3 ); 
INSERT INTO TR_TEST( ID, BUSINESS_KEY, LINKED_ID ) VALUES ( 3, 'entry_3', null ); 
INSERT INTO TR_TEST( ID, BUSINESS_KEY, LINKED_ID ) VALUES ( 1, 'entry_1', null ); 
INSERT INTO TR_TEST( ID, BUSINESS_KEY, LINKED_ID ) VALUES ( 2, 'entry_2', 1 ); 

我跑步时

DELETE FROM TR_TEST WHERE ID IN (1, 2);

语句执行失败,并显示此错误

  

[2019-09-10 18:01:51] [60000] [600] ORA-00600:内部Fehlercode,   参数:[13001],[],[],[],[],[],[],[],[],[],[],[]   [2019-09-10 18:01:51] java.lang.RuntimeException:错误:600,   位置:12,Sql =从TR_TEST WHERE ID IN(1、2)中删除,   OriginalSql =从TR_TEST WHERE ID IN(1,2)中删除,错误消息=   ORA-00600:内部专家费勒码,参数:[13001],[],[],[],[],   [],[],[],[],[],[],[]'

对于发生的错误消息,如果审核触发器是“删除前”或“删除后”,则没有任何区别。

但是删除一项又一项的工作并正确填写了审计表

DELETE FROM TR_TEST WHERE ID IN (1);
DELETE FROM TR_TEST WHERE ID IN (2);

以及删除不带WHERE子句的所有内容,这也可以正确填充审核表

DELETE FROM TR_TEST;

如果将外键级联规则更改为doNothing,则审计触发器也将起作用,但这不是此处想要的行为。

我做错什么了吗,或者这是一个真正的Oracle错误?您知道任何解决方法吗?

感谢您的帮助, 马吕斯

1 个答案:

答案 0 :(得分:3)

我已经在Oracle XE 18c上对此进行了测试,并重现了该问题。有好消息,有坏消息。好消息是,我想我知道导致该错误的原因。坏消息是你不会喜欢它。

线索在于触发器掷入ORA-00600所需的时间。很长时间了。这通常是递归或死锁超时的指示。这就是我在这里发生的事情:删除记录时,ON DELETE SET NULL子句执行 update 。这将导致触发器再次触发(因为它触发了before delete or update),这将执行另一个更新并触发该触发器,依此类推。最终,事务因ORA-00600而失败。如果我们删除该外键约束,不仅删除成功,它还会像那样完成!。根本没有时间。

所以绝对是问题所在的ON DELETE SET NULL子句。删除一条语句中的多行只是Oracle的不二之选。当我们可以分别删除每一行时,这应该没有什么区别,但是确实可以。这就是使它成为错误的原因。

无论如何,至少您有一个可复制的测试用例:支持者喜欢这些。