Ainda recomendaria o a utilização de uma transação autonoma.

O problema de trigger mutante tambem é propagado em referências cíclicas, para 
o caso em questão não vejo grandes problemas de utilizar a transação autonoma.

Atenciosamente,
Caio Spadafora.




________________________________
De: Sérgio Luiz Rodrigues Chaves <sergio.cha...@elumini.com.br>
Para: oracle_br@yahoogrupos.com.br
Enviadas: Quarta-feira, 25 de Novembro de 2009 11:59:13
Assunto: RES: [oracle_br] Trigger mutanting

  
Debby,

Vou listar o procedimento básico para resolver esse problema:

1)       Tenho a tabela funcionário com a seguinte estrutura:

CREATE TABLE FUNC

(

CD_MAT    NUMBER(3) NOT NULL PRIMARY KEY,

NR_GIT    NUMBER(2),

VL_SAL    NUMBER(9,2)

2)       Tenho uma trigger para atualizar o salário do funcionário.

CREATE OR REPLACE TRIGGER checa_salario

BEFORE UPDATE OF vl_sal, nr_git ON FUNC

FOR EACH ROW WHEN (NEW.nr_git < 56)

DECLARE

salario_minimo           NUMBER(5) := 0;

salario_maximo           NUMBER(5) := 0;

faixa                    EXCEPTION;

negativo                 EXCEPTION;

BEGIN

SELECT MIN(vl_sal), Max(vl_sal)

INTO salario_minimo, salario_maximo

FROM FUNC

WHERE nr_git = :new.nr_git;

IF (:NEW.vl_sal < salario_minimo OR

:NEW.vl_sal > salario_maximo) THEN

RAISE faixa;

ELSIF (:NEW.VL_SAL < :OLD.vl_sal) THEN

RAISE negativo;

END IF;

EXCEPTION

WHEN faixa THEN

RAISE_APPLICATION_ ERROR (-20225, 'Salário fora da faixa');

WHEN negativo THEN

RAISE_APPLICATION_ ERROR (-20230, 'Incremento negativo');

END;

Que quando executo dá erro de "multante", pois estou realizando uma consulta na 
mesma tabela que estou atualizando.

3)       Resolvendo.. .. Criei uma tabela temporária com a mesma estrutura de 
FUNC de nome TFUNC_MUT.

DROP TABLE TFUNC_MUT;

CREATE TABLE TFUNC_MUT

(

CD_MAT    NUMBER(3) NOT NULL PRIMARY KEY,

NR_GIT    NUMBER(2),

VL_SAL    NUMBER(9,2),

NR_ORDEM  NUMBER,--- nova coluna

STATUS    VARCHAR2(10) --- nova coluna

)

DROP SEQUENCE ORDEM

/

CREATE SEQUENCE ORDEM

ORDER

START WITH 1

NOCYCLE

/

4)       Recrio a trigger gravando na tabela temporária

CREATE OR REPLACE TRIGGER checa_salario

BEFORE UPDATE OF vl_sal, nr_git ON FUNC

FOR EACH ROW WHEN (NEW.nr_git < 56)

DECLARE

salario_minimo           NUMBER(5) := 0;

salario_maximo           NUMBER(5) := 0;

qtd                      NUMBER;

negativo                 EXCEPTION;

BEGIN

IF (:NEW.VL_SAL < :OLD.vl_sal) THEN

RAISE negativo;

ELSE

SELECT COUNT(*) INTO qtd FROM tfunc_mut

where cd_mat = :new.cd_mat;

IF qtd = 0 THEN

INSERT INTO TFUNC_MUT (cd_mat, vl_sal, nr_git, nr_ordem, status)

VALUES (:NEW.cd_mat, :NEW.vl_sal, :NEW.nr_git,

ordem.nextval, 'VALID');

:NEW.vl_sal := :OLD.vl_sal;

end if;

END IF;

EXCEPTION

WHEN negativo THEN

RAISE_APPLICATION_ ERROR (-20230, 'Incremento negativo');

END; 

5)       Crio nova trigger 

CREATE OR REPLACE TRIGGER checa_salario_ mut

AFTER UPDATE OF vl_sal, nr_git ON FUNC

DECLARE

cursor wc is SELECT * FROM tfunc_mut

WHERE status = 'VALID'

ORDER BY NR_ORDEM

FOR UPDATE;

salario_minimo           NUMBER(5) := 0;

salario_maximo           NUMBER(5) := 0;

faixa                    EXCEPTION;

TYPE TIPO_MUT IS TABLE OF TFUNC_MUT%ROWTYPE

INDEX BY BINARY_INTEGER;

TABMUT                   TIPO_MUT;

I                                   NUMBER := 0;

BEGIN

FOR wr IN wc LOOP

SELECT MIN(vl_sal), MAX(vl_sal)

INTO salario_minimo, salario_maximo

FROM func

WHERE nr_git = wr.nr_git;

IF wr.vl_sal < salario_minimo OR

wr.vl_sal > salario_maximo THEN

RAISE faixa;

ELSE

I := I + 1;

TABMUT(I) := WR;

UPDATE tfunc_mut SET status = 'INVALID';

END IF;

END LOOP;

FOR J IN 1..I LOOP

UPDATE func SET vl_sal = TABMUT(J).vl_ sal,

nr_git = TABMUT(J).nr_ git

WHERE cd_mat = TABMUT(J).cd_ mat;

END LOOP;

IF I > 0 THEN

DELETE FROM tfunc_mut;

END IF;

EXCEPTION

WHEN faixa THEN

DELETE FROM tfunc_mut;

RAISE_APPLICATION_ ERROR (-20230, 'Salário fora da faixa');

END;

/

Verifique se os códigos acima lhe ajudam para resolver seu problema.

Boa sorte.

Atenciosamente, Sérgio Chaves. 

____________ _________ _________ __

De: oracle...@yahoogrup os.com.br [mailto:oracle...@yahoogrup os.com.br] Em 
nome de Sergio Lucchini
Enviada em: quarta-feira, 25 de novembro de 2009 10:58
Para: oracle...@yahoogrup os.com.br
Assunto: RES: [oracle_br] Trigger mutanting

Isso ocorre quando vc precisa acessa a tabela onde esta a trigger. Vc pode 
declarar a sua trigger como Pragma Autonomous_Transact ion para eliminar esse 
erro.

Exemplo:

CREATE OR REPLACE TRIGGER nome_trigger AFTER UPDATE
ON nome_tabela REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE

Pragma Autonomous_Transact ion;

BEGIN
........

Sergio Lucchini

____________ _________ _________ __
De: oracle...@yahoogrup os.com.br <mailto:oracle_ br%40yahoogrupos .com.br>  
[mailto:oracle...@yahoogrup os.com.br <mailto:oracle_ br%40yahoogrupos .com.br> 
] Em nome de Débora Acácio
Enviada em: quarta-feira, 25 de novembro de 2009 09:41
Para: Grp Oracle
Assunto: [oracle_br] Trigger mutanting

Olá

Estou tendo um problema numa trigger que estou alterando... . está dando erro 
de trigger mutanting... alguém poderia me ajudar ?

Grata

Debby :)

____________ _________ _________ _________ _________ _________ _
Veja quais são os assuntos do momento no Yahoo! +Buscados
http://br.maisbusca dos.yahoo. com <http://br.maisbusca dos.yahoo. com> 

[As partes desta mensagem que não continham texto foram removidas]

No virus found in this incoming message.
Checked by AVG - www.avg.com
Version: 8.5.423 / Virus Database: 270.14.81/2524 - Release Date: 11/24/09 
19:37:00

[As partes desta mensagem que não continham texto foram removidas]

[As partes desta mensagem que não continham texto foram removidas]


 


      
____________________________________________________________________________________
Veja quais são os assuntos do momento no Yahoo! +Buscados
http://br.maisbuscados.yahoo.com

[As partes desta mensagem que não continham texto foram removidas]

Responder a