Os Compound Triggers, introduzidos no Oracle 11g, representam uma evolução significativa na arquitetura de triggers do Oracle Database. Esta funcionalidade avançada permite a consolidação de múltiplos pontos de disparo (firing points) em uma única unidade lógica, oferecendo um controle granular sobre o ciclo de vida das operações DML.
O que são Compound Triggers?
Imagine que você está organizando uma grande festa. Você precisa fazer coisas antes dos convidados chegarem, quando cada convidado chega, quando cada convidado sai e depois que todos foram embora. Um Compound Trigger é como um planejador de festas que pode lidar com todas essas etapas em um único lugar!
No mundo do Oracle PL/SQL, um Compound Trigger permite combinar diferentes tipos de triggers em um só. Isso inclui:
- Um trigger que dispara antes da ação principal (como um INSERT ou UPDATE)
- Um trigger que dispara antes de afetar cada linha
- Um trigger que dispara depois de afetar cada linha
- Um trigger que dispara após a ação principal ser concluída
Estrutura de um Compound Trigger
Vamos ver como é a estrutura básica de um Compound Trigger:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
CREATE OR REPLACE TRIGGER nome_do_trigger FOR evento_de_disparo ON nome_da_tabela COMPOUND TRIGGER -- Seção de Declarações BEFORE STATEMENT IS BEGIN -- Código executado antes da ação principal END BEFORE STATEMENT; BEFORE EACH ROW IS BEGIN -- Código executado antes de afetar cada linha END BEFORE EACH ROW; AFTER EACH ROW IS BEGIN -- Código executado após afetar cada linha END AFTER EACH ROW; AFTER STATEMENT IS BEGIN -- Código executado após a ação principal END AFTER STATEMENT; END; |
Exemplo Prático
Vamos criar um Compound Trigger para a tabela EMPLOYEES (que faz parte do schema HR no Oracle). Este trigger vai:
- Verificar se é dia útil antes de permitir alterações
- Registrar o usuário que fez a alteração
- Contar quantas linhas foram afetadas
- Registrar o total de alterações no log
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
CREATE OR REPLACE TRIGGER emp_compound_trg FOR INSERT OR UPDATE OR DELETE ON employees COMPOUND TRIGGER -- Seção de Declarações v_count NUMBER := 0; v_user VARCHAR2(30); BEFORE STATEMENT IS BEGIN -- Verifica se é dia útil IF TO_CHAR(SYSDATE, 'DY') IN ('SAT', 'SUN') THEN RAISE_APPLICATION_ERROR(-20001, 'Alterações não são permitidas nos fins de semana'); END IF; -- Registra o usuário v_user := USER; END BEFORE STATEMENT; BEFORE EACH ROW IS BEGIN -- Para INSERT e UPDATE, registra o usuário que fez a alteração IF INSERTING OR UPDATING THEN :NEW.last_updated_by := v_user; :NEW.last_update_date := SYSDATE; END IF; END BEFORE EACH ROW; AFTER EACH ROW IS BEGIN -- Conta as linhas afetadas v_count := v_count + 1; END AFTER EACH ROW; AFTER STATEMENT IS BEGIN -- Registra o total de alterações no log INSERT INTO hr_audit_log (action_date, action_user, action_type, rows_affected) VALUES (SYSDATE, v_user, CASE WHEN INSERTING THEN 'INSERT' WHEN UPDATING THEN 'UPDATE' WHEN DELETING THEN 'DELETE' END, v_count); END AFTER STATEMENT; END; |
Neste exemplo, criamos um Compound Trigger que:
- Verifica se é dia útil antes de permitir qualquer alteração
- Registra o usuário que está fazendo a alteração
- Atualiza informações de auditoria para cada linha inserida ou atualizada
- Conta quantas linhas foram afetadas
- Registra um resumo da operação em uma tabela de log
Vantagens dos Compound Triggers
- Código mais organizado: Todas as ações relacionadas estão em um único lugar.
- Melhor performance: Reduz a sobrecarga de ter múltiplos triggers separados.
- Compartilhamento de variáveis: As variáveis declaradas podem ser usadas em todas as seções.
- Resolução de problemas de “tabela mutante”: Ajuda a evitar erros comuns em triggers complexos.
Resolvendo o Problema da “Tabela Mutante”
Lembra daquele problema chato de “tabela mutante” que às vezes acontece com triggers normais? Os Compound Triggers podem ajudar a resolver isso!
Vamos ver um exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
CREATE OR REPLACE TRIGGER section_compound FOR INSERT OR UPDATE ON SECTION COMPOUND TRIGGER -- Seção de Declarações v_instructor_id INSTRUCTOR.INSTRUCTOR_ID%TYPE; v_instructor_name VARCHAR2(50); v_total INTEGER; BEFORE EACH ROW IS BEGIN IF :NEW.instructor_id IS NOT NULL THEN BEGIN v_instructor_id := :NEW.instructor_id; SELECT first_name || ' ' || last_name INTO v_instructor_name FROM instructor WHERE instructor_id = v_instructor_id; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR(-20001, 'Este não é um instrutor válido'); END; END IF; END BEFORE EACH ROW; AFTER STATEMENT IS BEGIN SELECT COUNT(*) INTO v_total FROM section WHERE instructor_id = v_instructor_id; -- Verifica se o instrutor atual está sobrecarregado IF v_total >= 10 THEN RAISE_APPLICATION_ERROR(-20000, 'Instrutor, ' || v_instructor_name || ', está sobrecarregado'); END IF; END AFTER STATEMENT; END; |
Neste exemplo, usamos um Compound Trigger para verificar se um instrutor está sobrecarregado (com mais de 10 seções) sem causar o erro de “tabela mutante”. Fazemos isso armazenando informações na seção BEFORE EACH ROW e fazendo a verificação final na seção AFTER STATEMENT.
Conclusão
Os Compound Triggers são uma ferramenta poderosa no arsenal do desenvolvedor Oracle PL/SQL. Eles permitem criar lógicas complexas de trigger de forma mais organizada e eficiente, além de ajudar a resolver problemas comuns como o da “tabela mutante”.
Lembre-se sempre de usar Compound Triggers com sabedoria. Eles são ótimos para cenários complexos, mas para triggers simples, os triggers tradicionais ainda podem ser a melhor opção.
Pratique bastante e você verá como os Compound Triggers podem tornar seu código mais limpo e eficiente. Boa codificação!