Introdução aos acionadores do PostgreSQL
Os gatilhos no PostgreSQL são procedimentos especiais que são executados ou acionados automaticamente quando ocorrem determinados eventos em uma tabela do banco de dados. Eles são usados para manter a integridade dos dados, aplicar regras comerciais e automatizar verificações ou transformações complexas.
Uso
Os acionadores são empregados para responder automaticamente a eventos como operações `INSERT`, `UPDATE` ou `DELETE` em uma tabela. Eles podem ser definidos para serem executados "ANTES", "DEPOIS" ou "DENTRO" do evento e, opcionalmente, podem ser condicionados ao fato de o evento ser bem-sucedido. Os acionadores podem ser definidos no nível da linha, sendo executados para cada linha afetada, ou no nível da instrução, sendo executados uma vez por instrução SQL.
CREATE TRIGGER trigger_name
{ BEFORE | AFTER | INSTEAD OF }
{ INSERT | UPDATE | DELETE }
ON table_name
FOR EACH { ROW | STATEMENT }
EXECUTE FUNCTION function_name();
Nessa sintaxe, `CREATE TRIGGER` define um novo acionador chamado `trigger_name` que chama uma função especificada `function_name` antes, depois ou em vez de um evento de modificação de dados em `table_name`.
Os acionadores interagem com os comandos de controle de transação, como `COMMIT` e `ROLLBACK`. Se um acionador causar um erro, a transação inteira normalmente será revertida, a menos que você a manipule explicitamente.
Exemplos
1. Acionador básico para auditoria
CREATE TABLE audit_log (
id SERIAL PRIMARY KEY,
operation VARCHAR(10),
operation_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE OR REPLACE FUNCTION log_insert() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO audit_log(operation) VALUES ('INSERT');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_audit
AFTER INSERT ON target_table
FOR EACH ROW
EXECUTE FUNCTION log_insert();
Esse exemplo básico registra cada operação `INSERT` em `target_table` na tabela `audit_log`.
2. Acionador com lógica condicional
CREATE OR REPLACE FUNCTION check_salary() RETURNS TRIGGER AS $$
BEGIN
IF NEW.salary < OLD.salary THEN
RAISE EXCEPTION 'Salary cannot be decreased!';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER salary_check
BEFORE UPDATE ON employees
FOR EACH ROW
EXECUTE FUNCTION check_salary();
Esse acionador garante que o salário de um funcionário não possa ser reduzido durante uma operação de atualização.
3. Acionador em cascata
CREATE OR REPLACE FUNCTION delete_cascade() RETURNS TRIGGER AS $$
BEGIN
DELETE FROM orders WHERE customer_id = OLD.id;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER cascade_delete
AFTER DELETE ON customers
FOR EACH ROW
EXECUTE FUNCTION delete_cascade();
Esse exemplo exclui automaticamente todos os pedidos associados a um cliente quando o cliente é removido.
Gerenciamento de acionadores
Para desativar ou eliminar um acionador quando ele não for mais necessário, você pode usar os seguintes comandos:
ALTER TABLE table_name DISABLE TRIGGER trigger_name;
DROP TRIGGER trigger_name ON table_name;
Para visualizar os acionadores existentes em um banco de dados, você pode consultar o catálogo do sistema `pg_trigger`.
Dicas e práticas recomendadas
- Mantenha os acionadores simples. A lógica complexa pode levar a gargalos de desempenho e desafios de manutenção.
- Faça um teste completo. Certifique-se de que seus acionadores funcionem conforme o esperado, testando-os em vários cenários.
- Acionadores de documentos. Documente claramente a finalidade e a operação de cada acionador para ajudar futuros desenvolvedores.
- Considere as permissões. Certifique-se de que os usuários que acionam os eventos tenham as permissões adequadas para executar as funções associadas.
- Monitore o impacto no desempenho. Esteja ciente de que o uso extensivo de acionadores pode afetar o desempenho, especialmente em tabelas com muitas transações.
- Evite acionadores recursivos. Os acionadores recursivos podem levar a loops infinitos e devem ser tratados com cautela.