O sistema de regras (rule system) do PostgreSQL oferece grande flexibilidade quando é necessário implementar determinadas regras de negócio. Assim como os triggers, as rules, também chamadas de regras, são acionadas quando um determinado evento ocorrer em uma tabela. Esse evento pode ser:
- INSERT
- UPDATE
- DELETE
- SELECT
As ações resultantes de uma regra podem ser complementares ou em substituição ao comando que aciona uma regra. Com esse artigo, espera-se que o leitor fique habilitado para fazer o uso do sistema de rules do PostgreSQL para estender e dar mais flexibilidade às suas aplicações.
Create Rule in PostgreSQL
O comando responsável pela criação de uma rule é o CREATE RULE. Sua sintaxe é apresentada abaixo:
CREATE [ OR REPLACE ] RULE NomeDaRule AS ON evento
TO Tabela [ WHERE CondiçãoLógica]
DO [ ALSO | INSTEAD ] { NOTHING | comando | ( comando ; comando ... ) }
Onde:
- NomeDaRule: indica qual evento está associado à regra. Os eventos podem ser: INSERT, UPDATE, DELETE e SELECT. Somente um evento pode ser definido.
- Evento: indica qual evento está associado à regra. Os eventos podem ser: INSERT, UPDATE, DELETE e SELECT. Somente um evento pode ser definido.
- Tabela: a tabela a qual a rule está associada.
- CondiçãoLógica: uma condição que aciona a regra. Não é possível utilizar outras tabelas ou uma função de agregação.
- ALSO e INSTEAD: indica se o comando que acionou a rule e os comandos definidos serão executados (ALSO) ou se o comando original será substituído (INSTEAD).
- Comando: especifica o comando SQL a ser executado por essa rule. Uma rule do tipo SELECT não suporta mais de um comando. Entretanto, pode-se especificar mais de um comando colocando-os entre parênteses e separando-os por ponto-e-vírgula para os demais tipos.
DevCast: Você usa Triggers?
NEW e OLD
O nome especial de tabela NEW pode ser utilizado para referenciar os novos valores inseridos (ON INSERT) ou atualizados (ON UPDATE) em uma tabela. Já nome especial OLD contém os valores apagados através de um DELETE ou UPDATE.
Exemplo:
Vamos criar uma rule de auditoria em uma tabela que mantém os dados de funcionários de uma empresa, como mostra a Figura 1. Nos exemplos utilizaremos as funções current_user, que retorna o usuário conectado ao banco de dados, e o current_timestamp, que retorna a data e a hora atual.
O primeiro passo é criar uma tabela de auditoria que será atualizada toda vez que o salário de um funcionário for modificado (Listagem 1). Essa tabela terá o número do funcionário (n_emp), o novo salário (novo_sal), o usuário que efetuou a alteração (usuario) e a data mais a hora em que a alteração ocorreu (datahora).
CREATE TABLE emp_log (
n_emp int,
novo_sal decimal(10,2),
usuario varchar(50),
datahora timestamp);
O comando para criação da rule é apresentado na Listagem 2.
CREATE RULE log_emp_rule AS ON UPDATE TO emp
WHERE NEW.sal <> OLD.sal
DO INSERT INTO emp_log
VALUES (NEW.n_emp, NEW.sal, current_user, current_timestamp);
Note que a parte em destaque na Listagem 2 nos mostra que essa regra só será acionada quando o salário novo (NEW.sal) e o salário antigo (OLD.sal) forem diferentes, indicando portanto, uma alteração no valor da coluna sal, que contém o salário dos funcionários.
O comando da Listagem 3 atualiza o salário de um determinado funcionário e aciona a regra log_emp_rule inserindo um novo registro na tabela de auditoria.
UPDATE emp SET sal = sal * 1.1
WHERE n_emp = 110;
Um detalhe importante é que caso exista mais de uma rule em uma tabela, a ordem de acionamento segue a ordem alfabética do nome das rules.
Substituindo comandos
Para substituir um comando original por aqueles definidos na ação de uma rule, basta utilizar a palavra-chave INSTEAD. A Listagem 4 mostra o comando da Listagem 2 reescrito.
CREATE RULE log_emp_rule AS ON UPDATE TO emp
WHERE NEW.sal <> OLD.sal
DO INSTEAD INSERT INTO emp_log VALUES (NEW.n_emp,
NEW.sal, current_user, current_timestamp);
Essa nova regra define que o comando original de atualização que acionar a regra será ignorado, executando apenas o comando complementar definido.
Caso o comando de atualização (Listagem 3) seja executado, com essa nova regra, a tabela emp não será afetada, mas a tentativa de fazê-lo será gravada na tabela emp_log.
Ignorando comandos
Para ignorar o comando original e não definir ações complementares, pode-se utilizar a palavra-chave NOTHING em conjunto com o INSTEAD. A Listagem 5 mostra o comando da Listagem 2 reescrito.
CREATE RULE log_emp_rule AS ON UPDATE TO emp
WHERE NEW.sal <> OLD.sal
DO INSTEAD NOTHING;
Caso um comando acione essa regra, ele será ignorado sem gerar qualquer tipo de erro para o usuário, e as tabelas emp e emp_log não terão qualquer alteração.
Rules e views
As views são muito utilizadas para gravar no banco de dados uma consulta em uma ou mais tabelas para a visualização de dados. No PostgreSQL, as views podem ser implementadas utilizando o sistema de rules.
CREATE VIEW empv AS SELECT nome_emp, n_emp FROM emp;
Apesar de não ser prático, a view criada na Listagem 6 também poderia ser criada com os dois passos apresentados na Listagem 7, que são exatamente as operações internas realizadas pelo PostgreSQL quando criamos uma view.
CREATE TABLE empv (nome_emp varchar(30), n_emp int);
CREATE RULE “_RETURN” AS ON SELECT TO empv
DO INSTEAD SELECT nome_emp, n_emp FROM emp;
Views atualizáveis
Geralmente as views são utilizadas apenas para visualização de dados, não permitindo a execução de comandos como INSERT, UPDATE e DELETE. Entretanto, o recurso de views atualizáveis permite que essas modificações sejam refletidas na tabela a qual uma view está associada. A Listagem 8 mostra a implementação de uma view atualizável baseada na view da Listagem 6.
CREATE RULE empv_rule AS ON INSERT TO empv
DO INSTEAD INSERT INTO emp (n_emp, nome_emp, sal)
VALUES (NEW.n_emp, NEW.nome_emp, NEW.sal);
O comando de inserção que for aplicado sobre a view será redirecionado para a tabela emp.
Apagando uma rule
DROP RULE NomeDaRule ON Tabela
Onde:
- NomeDaRule: nome da rule que será apagada.
- Tabela: nome da tabela onde a rule se encontra.
Triggers versus rules
Apesar de desempenharem papéis semelhantes, existem diferenças fundamentais entre rules e triggers. Portanto, é necessário escolher corretamente quando utilizar cada uma.
Quando uma rule é acionada, o comando que a acionou é reescrito ou um (ou mais) novo comando é gerado para executar os procedimentos definidos. A chamada da rule acontece antes da execução do comando original. Devido a esse comportamento, uma rule é acionada uma única vez, ao contrário dos triggers que são executados para cada linha afetada pelo comando que o disparou. Podemos pensar em triggers como uma reação à modificação dos dados de uma tabela. Normalmente esta reação é utilizada para implementar regras de negócio mais complexas. Vale lembrar que a funcionalidade rule é um recurso específico do PostgreSQL, dificultando o porte para outros bancos de dados.
Outra diferença está relacionada com a diversidade de comandos suportados. Em rules, só são permitidos comandos SQL, ao contrário dos triggers que possibilitam o uso das mais diversas linguagens procedurais suportadas pelo PostgreSQL, como: PL/pgSQL, C, Perl. Como regra geral, os triggers são indicados para as situações onde regras de negócio devem ser acionadas devido a certas modificações de dados.
Tabelas de sistema sobre rules
A view pg_rules contém informações das rules (Tabela 1). Existe também a tabela pg_rewrite que possui algumas informações mais detalhadas.
Nome | Tipo | Descrição |
---|---|---|
schemaname | Name | Schema que contém a tabela onde a regra se encontra. |
tablename | Name | Nome da tabela onde a regra se encontra. |
rulename | Name | Nome da regra. |
definition | Text | Código fonte da regra. |
Tabela 1. Campos da view pg_rules.
Conclusão
Apresentamos neste artigo um recurso pouco conhecido e, por isto, raramente utilizado do banco de dados PostgreSQL. Por se tratar de um recurso simples de implementar, uma vez que somente código SQL é utilizado, as rules são um complemento ao uso de triggers.
As rules podem criar novas possibilidades de modificar o comportamento de um comando SQL e também possibilitar o uso de funcionalidades novas sobre views, como atualização, remoção e inserção.
Conteúdos recentes
- Ajax com jQuery: Como evitar múltiplas requisições ao servidor: Aprenda neste conteúdo como bloquear um botão utilizando jQuery, algo muito útil para evitar múltiplos cliques e, consequentemente, várias requisições ao servidor.
- Como fazer um CRUD 1:N no Laravel: Neste curso veremos como desenvolver um CRUD em Laravel com duas entidades que se relacionam de forma 1N.
- ASP.NET MVC ViewBag: Como enviar dados do controller para a view: Aprenda a utilizar o ViewBag, um mecanismo para efetuar o tráfego de dados do controller para a view no ASP.NET MVC.
Saiba mais sobre Triggers e SQL Server ;)
- Update Triggers: Como proteger tabelas de SQL Injection: Veja neste DevCast como implementar uma trigger que servirá de segunda camada de segurança no banco de dados e aprenda a garantir a segurança necessária para executar o comando update.
- Trabalhando com Triggers DML no Oracle: Neste artigo trabalharemos com o conceito de Triggers no Oracle, onde veremos o porquê e quando devemos utilizá-las. Para isso utilizaremos exemplos simples de triggers compostas.
- MySQL Básico: Triggers: Veja neste artigo como utilizar triggers no banco de dados MySQL para automatizar ações com base em eventos ocorridos nas tabelas, como inclusão e exclusão de registros.
- Triggers no SQL Server: teoria e prática aplicada em uma situação real: Veja neste artigo como trabalhar com triggers no SQL Server, entendendo seu funcionamento e como criá-los, com base em um exemplo que reflete uma situação real.