O
ELSE ramo pode ser radicalmente simplificado. Mas mais algumas coisas são ineficientes / imprecisas / perigosas:CREATE OR REPLACE FUNCTION sample_trigger_func()
RETURNS TRIGGER AS
$func$
BEGIN
IF TG_OP = 'DELETE' THEN
RAISE INFO 'OLD: %', OLD.name;
EXECUTE format('INSERT INTO %I SELECT ($1).*', TG_TABLE_NAME || '_deletes')
USING OLD #= hstore('{mod_op, mod_datetime}'::text[]
, ARRAY[left(TG_OP, 1), now()::text]);
RETURN OLD;
ELSE -- insert, update
NEW.mod_op := left(TG_OP, 1);
NEW.mod_datetime := now();
RETURN NEW;
END IF;
END
$func$ LANGUAGE plpgsql;
-
NoELSEbranch apenas atribua aNEWdiretamente. Não há necessidade de SQL mais dinâmico - o que dispararia o mesmo gatilho novamente, causando um loop infinito. Esse é o erro primário.
-
RETORNAR NOVO;fora doSEconstrução quebraria sua função de gatilho paraDELETE, poisNOVOnão é atribuído para DELETEs.
-
Um recurso importante é o uso dehstoree o operador hstore#=para alterar dinamicamente dois campos selecionados do tipo de linha conhecido - que é desconhecido no momento de escrever o código. Dessa forma, você não adultera oOLDoriginal valor, o que pode ter um efeito colateral surpreendente se você tiver mais gatilhos na cadeia de eventos.
OLD #= hstore('{mod_op, mod_datetime}'::text[] , ARRAY[left(TG_OP, 1), now()::text]);
O módulo adicionalhstoreDeve ser instalado. Detalhes:
- Como definir o valor do campo de variável composta usando SQL dinâmico
- Passando nomes de colunas dinamicamente para uma variável de registro no PostgreSQL
Usando ohstore(text[], text[])variante aqui para construir umhstorevalor com vários campos em tempo real.
-
O operador de atribuição em plpgsql é:=:
-
Observe que usei o nome da colunamod_datetimeem vez do enganosomod_date, já que a coluna é obviamente umtimestampe não umadata.
Eu adicionei algumas outras melhorias enquanto estava nisso. E o próprio gatilho deve ficar assim:
CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();
SQL Fiddle.