2

.

Hello swarm intelligence, here's the problem, I can't seem to solve without a little help from the StackOverflow crowd :)

Given this Oracle Database

  • Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit
  • Production PL/SQL Release 12.1.0.2.0 - Production
  • "CORE 12.1.0.2.0 Production" TNS for Solaris: Version 12.1.0.2.0 -
  • Production NLSRTL Version 12.1.0.2.0 - Production

And this DDL and data:

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 ); 

When I run

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

statement execution fails with this error

[2019-09-10 18:01:51] [60000][600] ORA-00600: Interner Fehlercode, Argumente: [13001], [], [], [], [], [], [], [], [], [], [], [] [2019-09-10 18:01:51] java.lang.RuntimeException: Error : 600, Position : 12, Sql = DELETE FROM TR_TEST WHERE ID IN (1, 2), OriginalSql = DELETE FROM TR_TEST WHERE ID IN (1, 2), Error Msg = ORA-00600: Interner Fehlercode, Argumente: [13001], [], [], [], [], [], [], [], [], [], [], []'

For the error message to occur, it makes no difference, if the audit trigger is BEFORE DELETE or AFTER DELETE.

But deleting everything one after another works and fills the audit table correctly

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

As well as deleting everything without WHERE clause, which also fills the audit table correctly

DELETE FROM TR_TEST;

The audit triggers also work, if one changes the foreign keys cascade rule to doNothing, but that is not the wanted behavior here.

Am I doing something wrong, or is this a real Oracle bug? Do you know any workaround?

Thanks for your help, Marius

APC
  • 144,005
  • 19
  • 170
  • 281
Marius Schmidt
  • 633
  • 6
  • 18
  • 2
    ORA-00600 is Oracle's standard code for unhandled design side-effects i.e. Oracle bugs. The standard advice is, you need to contact Oracle Support. These things are dependent on OS platform, database version, patch level, etc. Unless it's a common thing - and Google suggests it's not in this case - there's very little we can do to advise you. If you don't have a Support contract you may be out of luck. There's nothing egregious about your code, on the face of it it ought to work. – APC Sep 10 '19 at 16:23
  • Hi APC and thx for your comment, I am requesting my customer to file a bug report then and keep us informed, if I get an answer. I would still be interested, if the problem occurs for others as well? I am a bit baffled that this bug even exists, because it seemed not so uncommon to me, to use some audit trigger in combination with some foreignKey cascading... – Marius Schmidt Sep 10 '19 at 16:33

1 Answers1

3

I have tested this on my Oracle XE 18c and have reproduced the problem. There's good news and bad news. The good news is I think I know what causes the error. The bad news is you're not going to like it.

The clue is in the time it takes for the trigger to hurl ORA-00600. It's a long time. This is often an indicator of recursion or a deadlock timeout. And that's what I think is happening here: when you delete a record the ON DELETE SET NULL clause executes an update. That causes the trigger to fire again (because it fires before delete or update), which executes another update and fires the trigger, and so on. Eventually the transaction fails with ORA-00600. If we drop that foreign key constraint not only does the delete succeed it finishes like that!. No time at all.

So it's definitely the ON DELETE SET NULL clause which is the problem. There's just something about deleting multiple rows in one statement which causes Oracle to blow a fuse. This shouldn't make a difference when we can delete each row individually but it does. That's what makes it a bug.

Anyway, at least you have a reproducible test case: Support likes those.

APC
  • 144,005
  • 19
  • 170
  • 281
  • Thank you for taking your time to verify. Let's see, what they make of it. – Marius Schmidt Sep 10 '19 at 16:56
  • 1
    As far as I can see the single trigger only causes the error if it refers (in any way - even if stripped down to a single `dbms_output` call) to `:OLD.LINKED_ID`. Which is, of course, the column being nulled. Interesting. Although having said that, it also fails quite quickly for me, in 11.2.0.4, so maybe there's more than one thing going on... (The workaround works in 11gR2, incidentally.) – Alex Poole Sep 10 '19 at 17:08
  • Yes, just now. Unfortunately it is not working for me, but that might be explainable by your more current Oracle version. May it help other nonetheless. EDIT: It takes a few seconds to fail for me – Marius Schmidt Sep 10 '19 at 17:08
  • I can confirm Alex test, that leaving out the mapping of LINKED_ID <-> :OLD.LINKED_ID the trigger works correctly both with separate triggers as well as combined trigger for insert and update. – Marius Schmidt Sep 10 '19 at 17:20
  • Using DELETE without WHERE results into a different audit trail than using WHERE ID IN (1,2). First one only shows two 'D'eletes, while the latter results into two 'D'eletes and one 'U'pdate. – Marius Schmidt Sep 10 '19 at 17:29
  • 1
    Alas the two trigger solution didn't solve the problem. There was a bug in my code too embarrassing to admit ;-) – APC Sep 10 '19 at 17:41