Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming PL SQL.doc
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
5.06 Mб
Скачать

18.1.5 Mutating Table Errors: Problem and Solution

When something mutates, it is changing. Something that is changing is hard to analyze and to quantify. A mutating table error (ORA-4091) occurs when a row-level trigger tries to examine or change a table that is already undergoing change (via an INSERT, UPDATE, or DELETE statement).

In particular, this error occurs when a row-level trigger attempts to read or write the table from which the trigger was fired. Suppose, for example, that I want to put a special check on my employee table to make sure that when a person is given a raise, that person's new salary is not more than 20% above the next-highest salary in their department.

I would therefore like to write a trigger like this:

CREATE OR REPLACE TRIGGER brake_on_raises

BEFORE UPDATE OF salary ON employee

FOR EACH ROW

DECLARE

l_curr_max NUMBER;

BEGIN

SELECT MAX (salary) INTO l_curr_max

FROM employee;

IF l_curr_max * 1.20 < :NEW.salary

THEN

errpkg.RAISE (

employee_rules.en_salary_increase_too_large,

:NEW.employee_id,

:NEW.salary

);

END IF;

END;

But when I try to perform an update that, say, doubles the salary of the PL/SQL programmer (yours truly), I get this error:

ORA-04091: table SCOTT.EMPLOYEE is mutating, trigger/function may not see it

Here are some guidelines to keep in mind regarding mutating table errors:

  • In general, a row-level trigger may not read or write the table from which it has been fired. The restriction only applies torow-level triggers, however. Statement-level triggers are free to both read and modify the triggering table; this fact gives us a way to avoid the mutating table error, as discussed in Section 18.1.5.2.

  • If you make your trigger an autonomous transaction (by adding the PRAGMA AUTONOMOUS TRANSACTION statement and committing inside the body of the trigger), then you will be able to query the contents of the firing table. However, you will still not be allowed to modify the contents of the table.

18.1.5.1 Mutating tables and foreign keys

The mutating table error often arises in the context of foreign keys. Let's take a look at an example.

The staff at Humongous Bank have implemented their transaction system using Version 7.3.4 of Oracle, and they are feeling very magnanimous: they have decided to give away $100 to any customer who opens up a new account. As usual, they neglected to inform the applications team until the weekend before the promotion begins; thus poor Kay Fourohone is asked to work through the weekend to implement the new system.

Kay applies her stellar logic to the situation—every time an account is opened, a deposit of $100 must be made into my . . . I mean, the new account. This is a perfect application of DML triggers: every time an INSERT is performed on the account table, a trigger will put the deposit entry into the account transaction table. Kay is extremely happy because such a simple trigger will only take half a day to code, debug, test, and implement, leaving her the rest of the weekend to practice bowling before the league finals on Monday.

Knowing that the tables involved are account and account_transaction and that there is a foreign key between them on the account_id field, Kay creates the following trigger:

CREATE TRIGGER give_away_free_money

AFTER INSERT ON account

FOR EACH ROW

BEGIN

INSERT INTO account_transaction

(transaction_id,

account_id,

transaction_type,

transaction_amount,

comments)

VALUES(account_transaction_seq.nextval,

:NEW.account_id,

'DEP',

100,

'Free Money!');

END;

Kay is so confident that this will work that she almost doesn't bother to test it. What could go wrong with such a simple chunk of code? She quickly gets her answer.

SQL> INSERT INTO account

2 (account_id,account_owner)

3 VALUES(1,'Test');

INSERT INTO account

*

ERROR at line 1:

ORA-04091: table SCOTT.ACCOUNT is mutating, trigger/function may not see it

ORA-06512: at "SCOTT.GIVE_AWAY_FREE_MONEY", line 2

ORA-04088: error during execution of trigger 'SCOTT.GIVE_AWAY_FREE_MONEY'

The account table is indeed mutating during this transaction as a result of the initial INSERT statement. The trigger then attempts to insert a record into the account_transaction table, which in turn requires Oracle to validate the account_id against the account table. But because foreign key validation occurs before the trigger even fires, Oracle cannot be assured that the entry is valid.

Now you may be saying that this error makes no sense because all of the required information is easily available; the primary key is available from the original INSERT statement. While this is a valid argument, the fact remains that we've exposed a limitation of row-level triggers here.

As of Oracle 8.1.5, this error will no longer occur. The foreign key check now takes place after row-level triggers fire.

This limitation applies only to row-level triggers; statement-level triggers are immune because they do not process single rows. This immunity is what Kay will exploit to get around her mutation problem.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]