O erro do gatilho de mutação do Oracle ocorre quando um gatilho faz referência à tabela que possui o gatilho, resultando na mensagem “ORA-04091:nome da tabela está mudando, gatilho/função pode não vê-lo”.
Vamos dar uma olhada nas soluções alternativas existentes.
O primeiro, através do pacote, é antigo e parece ser eficaz, porém, leva muito tempo para prepará-lo e executá-lo. O segundo é simples e executado usando gatilhos compostos.
create table turtles as select 'Splinter' name, 'Rat' essence from dual union all select 'Leonardo', 'Painter' from dual union all select 'Rafael', 'Painter' from dual union all select 'Michelangelo', 'Painter' from dual union all select 'Donatello', 'Painter' from dual;
Quando Splinter se transforma de rato em sensei, os pintores terão que se transformar automaticamente em ninjas. Este gatilho parece ser adequado:
create or replace trigger tr_turtles_bue before update of essence on turtles for each row when ( new.name = 'Splinter' and old.essence = 'Rat' and new.essence = 'Sensei' ) begin update turtles set essence = 'Ninja' where essence = 'Painter'; end;
No entanto, ao atualizar o registro:
update turtles set essence = 'Sensei' where name = 'Splinter'
Ocorre o seguinte erro:
ORA-04091:a tabela SCOTT.TURTLES está em mutação, o gatilho/função pode não vê-la
Vamos excluir este gatilho:
drop trigger tr_turtles_bue;
O método 1: Usando o pacote e o gatilho de nível de instrução.
create or replace package pkg_around_mutation is bUpdPainters boolean; procedure update_painters; end pkg_around_mutation; / create or replace package body pkg_around_mutation is procedure update_painters is begin if bUpdPainters then bUpdPainters := false; update turtles set essence = 'Ninja' where essence = 'Painter'; end if; end; end pkg_around_mutation; / create or replace trigger tr_turtles_bue before update of essence on turtles for each row when ( new.name = 'Splinter' and old.essence = 'Rat' and new.essence = 'Sensei' ) begin pkg_around_mutation.bUpdPainters := true; end tr_turtles_bue; / create or replace trigger tr_turtles_bu after update on turtles begin pkg_around_mutation.update_painters; end tr_turtles_bu; /
O método 2: Usando gatilhos DML compostos (disponíveis a partir do Oracle 11g).
create or replace trigger tr_turtles_ue for update of essence on turtles compound trigger bUpdPainters boolean; before each row is begin if :new.name = 'Splinter' and :old.essence = 'Rat' and :new.essence = 'Sensei' then bUpdPainters := true; end if; end before each row; after statement is begin if bUpdPainters then update Turtles set essence = 'Ninja' where essence = 'Painter'; end if; end after statement; end tr_turtles_ue;
Vamos tentar o seguinte:
update turtles set essence = 'Sensei' where name = 'Splinter'
Mesmo que você tenha enfrentado um caso mais complexo de mutação, você pode usar a ideia acima mencionada como uma solução alternativa. No trigger de nível de instrução, diferentemente do trigger de nível de linha, nenhuma mutação ocorre. Você pode usar variáveis (tags, latches, tabelas PL SQL) em um pacote adicional ou variáveis que são globais para todas as seções do trigger composto, o que é preferível a partir da versão Oracle 11g. Então, agora você também conhece o kung fu.
Você pode encontrar informações adicionais sobre gatilhos em:Compound DML Triggers
Sinta-se à vontade para adicionar quaisquer comentários.