'Could someone explain to me why this trigger does NOT cause a mutating table error?

I have the following row-level trigger, which does both a selection and an update on the same table:

CREATE OR REPLACE TRIGGER insert_product 
    BEFORE INSERT ON products
    FOR EACH ROW
    DECLARE     
            max_version NUMBER (4, 2);
            not_newest EXCEPTION;
    BEGIN
            SELECT version INTO max_version
                FROM (SELECT CIF, name, max(version) AS version FROM products GROUP BY CIF, name 
                HAVING CIF = :NEW.cif AND name = :NEW.name);
            
            IF max_version >= :NEW.version THEN
                RAISE not_newest;
            END IF;
                
            UPDATE products
            SET retired = sysdate
            WHERE CIF = :NEW.cif AND name = :NEW.name AND retired IS NULL;

    EXCEPTION
            WHEN no_data_found THEN NULL;
            WHEN not_newest THEN raise_application_error(-20001, 'Invalid version');
    END insert_product;
/

So the thing is, since it's selecting and updating the same table, why doesn't it throw a mutating table error when I execute it?

I've tested it with queries that affect multiple rows and nothing seems to cause the error, it works properly, which is pretty great I guess, but I would like to understand why.



Solution 1:[1]

Your trigger does cause a mutating-table error if I insert multiple rows at the same time using INSERT INTO ... SELECT ...:

SQL> insert into products (cif) select 1 from dual union all select 2 from dual;
insert into products (cif) select 1 from dual union all select 2 from dual
            *
ERROR at line 1:
ORA-04091: table LUKE.PRODUCTS is mutating, trigger/function may not see it
ORA-06512: at "LUKE.INSERT_PRODUCT", line 5
ORA-04088: error during execution of trigger 'LUKE.INSERT_PRODUCT'

Interestingly, the mutating-table error also arises if I use INSERT INTO ... SELECT ... to insert only one row:

SQL> insert into products (cif) select 1 from dual;
insert into products (cif) select 1 from dual
*
ERROR at line 1:
ORA-04091: table LUKE.PRODUCTS is mutating, trigger/function may not see it
ORA-06512: at "LUKE.INSERT_PRODUCT", line 5
ORA-04088: error during execution of trigger 'LUKE.INSERT_PRODUCT'

I don't get the mutating-table error if I use INSERT INTO ... VALUES ..., however:

SQL> insert into products (cif) values (1);

1 row created. 

I can only guess at the reason why you don't get the exception in this case. Before the first row gets inserted the table hasn't yet started mutating, so the data in the table can be queried because it hasn't yet changed. I'd definitely expect a mutating-table error when inserting multiple rows: after inserting the first row and before inserting the second row the table definitely is mutating. However, it's less clear to me why inserting a single row with INSERT INTO ... SELECT ... does cause the error.

Finally, I don't know what columns are in your table besides those mentioned in the trigger, and I don't know which ones are nullable, so for the purpose of this answer I made them all nullable and just inserted a value into one of them.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Luke Woodward