Sistemas de Informação Rules and Triggers André Restivo Sistemas de Informação 2006/07
Rules e Triggers Nem todas as restrições podem ser definidas usando os mecanismos que estudamos anteriormente: - CHECK - NOT NULL - FOREIGN KEY - UNIQUE KEY - PRIMAY KEY A maior parte das Bases de Dados oferece um mecanismo de triggers que permite executar código quando uma certo evento acontece na Base de Dados (por exemplo, quando uma nova linha é inserida numa tabela) Para além deste mecanismo, o PostrgreSQL também permite a captura de eventos de outra forma, mais simples mas não tão poderosa, usando rules (regras).
Rules Ao contrário dos triggers, as regras modificam a query que está ser executada. Em PostgreSQL as vistas são modeladas internamente como regras. Uma regra tem a seguinte sintaxe: CREATE RULE rule_name AS ON event TO object [WHERE rule_qualification] DO [INSTEAD] [action (actions) NOTHING];
Sintaxe CREATE RULE rule_name AS ON event TO object [WHERE rule_qualification] DO [INSTEAD] [action (actions) NOTHING]; Uma regra é disparada quando um certo evento (select, insert, update ou delete) é disparado sobre um certo objecto (relação ou tabela). Quando esse evento é disparado a regra executa algumas acções depois, antes ou em vez do evento original. Pode ainda simplesmente suprimir o evento original.
Ordem de Execução No caso de regras sobre eventos do tipo insert, as novas acções são executadas antes das linhas da query original serem inseridas na tabela. No caso de regras sobre eventos do tipo delete ou update, as novas acções são executadas depois das linhas da query original serem inseridas na tabela. Isto se a regra não for do tipo instead.
Utilização As regras permitem, por exemplo, criar uma forma alternativa de fazer update numa tabela: CREATE RULE rule_produto_ins AS ON insert TO produto_chegou DO INSTEAD UPDATE produto SET stock = stock + NEW.quantidade; A pseudo-linha NEW permite aceder aos valores que iriam ser introduzidos originalmente.
Utilização Podemos ainda, por exemplo, fazer log de todas as alterações numa determinada tabela. CREATE RULE rule_utilizador_log_ins AS ON insert TO utilizador DO INSERT INTO utilizador_log VALUES (NEW.id, NEW.login, C, now); CREATE RULE rule_utilizador_log_upd AS ON update TO utilizador DO INSERT INTO utilizador_log VALUES (NEW.id, NEW.login, U, now);
Triggers Os triggers são um mecanismo muito mais complexo que as regras mas também muito mais poderoso. Os triggers definem funções a serem executadas antes ou depois de um determinado tipo de queries. Antes de criarmos um trigger temos de definir uma função apropriada: - Tem de retornar o tipo trigger. - Não pode receber parâmetros.
Funções Uma função associada a um trigger pode fazer uma de três coisas (se for do tipo before): - não inserir/modificar ou apagar a linha em questão retornando null; - modificar a linha a inserir ou modificar; - retornar um erro. Se o trigger for do tipo after pode retornar null.
Precauções Um trigger pode executar um comando que provoque a execução de um outro trigger. Isto pode dar origem a uma recursão infinita que a BD não detecta automaticamente.
Sintaxe A sintaxe usada para criar um trigger é a seguinte: CREATE TRIGGER <name> BEFORE AFTER INSERT OR UPDATE OR DELETE ON <tablename> [FOR EACH ROW] EXECUTE PROCEDURE <function>();
Implementação das funções As funções associadas aos triggers podem ser criadas usando várias linguagens. O C é a linguagem por defeito mas outras podem ser instaladas como por exemplo o pgplsql.
PL/pgSQL Sistemas de Informação 2006/07
CREATE FUNCTION CREATE FUNCTION soma(a INTEGER, b INTEGER) RETURNS INTEGER AS ' DECLARE res INTEGER; BEGIN res := a + b; return res; END; ' LANGUAGE plpgsql;
Query Sem Resultados CREATE FUNCTION apagaempregado(id INTEGER) RETURNS VOID AS ' BEGIN DELETE FROM empregado WHERE emp_id = id; PERFORM * FROM empregado WHERE emp_id = id; IF FOUND THEN RAISE EXCEPTION ''empregado não apagado ''; END IF; END; ' LANGUAGE plpgsql;
Query Com 1 Resultado CREATE FUNCTION getnomeempregado(id INTEGER) RETURNS VARCHAR AS ' DECLARE record RECORD; BEGIN SELECT * INTO record FROM empregado WHERE emp_id = id; IF NOT FOUND THEN RAISE EXCEPTION ''empregado % não existente'', id; END IF; RETURN record.emp_nome; END; ' LANGUAGE plpgsql;
Query Com Vários Resultados CREATE FUNCTION getsomasalarios(dep INTEGER) RETURNS INTEGER AS ' DECLARE soma INTEGER := 0; emp RECORD; BEGIN FOR emp IN SELECT * FROM empregado WHERE dep_id = dep LOOP soma := soma + emp.emp_salario; END LOOP; RETURN soma; END; ' LANGUAGE plpgsql;
Ciclos WHILE NOT boolean_expression LOOP -- some computations here END LOOP; FOR i IN 1..10 LOOP -- some computations here RAISE NOTICE 'i is %', i; END LOOP;
Condições IF boolean_expression THEN -- some computations here ELSIF boolean_expression THEN -- some computations here ELSE -- some computations here END IF;
Funções para Triggers CREATE FUNCTION verificatipoempregado() RETURNS TRIGGER AS ' BEGIN IF NEW.emp_tipo = ''adm'' AND NEW.emp_password IS NULL THEN RAISE EXCEPTION ''os admins têm de ter pass''; END IF; RETURN NEW; -- Retorna a linha a ser inserida END; ' LANGUAGE PLPGSQL; CREATE FUNCTION descidapermissoes() RETURNS TRIGGER AS ' BEGIN IF OLD.emp_tipo = ''adm'' AND NEW.emp_tipo = ''emp'' THEN RAISE EXCEPTION ''os admins não podem perder permissões''; END IF; RETURN NEW; -- Retorna a linha a ser modificada END; ' LANGUAGE PLPGSQL;