PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Como evitar chamadas de gatilho em loop no PostgreSQL 9.2.1


Você pode fazer isso com gatilhos padrão BEFORE UPDATE OF ... ON ... .
O manual sobre CREATE TRIGGER informa:

O gatilho só será acionado se pelo menos uma das colunas listadas for mencionada como destino do comando UPDATE.

E mais abaixo:

Um gatilho específico de coluna (um definido usando a sintaxe UPDATE OF column_names) será acionado quando qualquer uma de suas colunas for listada como alvos na lista SET do comando UPDATE. É possível que o valor de uma coluna seja alterado mesmo quando o gatilho não é acionado, porque as alterações feitas no conteúdo da linha pelos gatilhos BEFORE UPDATE não são consideradas.

Minha ênfase em negrito. Portanto, sem loops infinitos, porque as atualizações dentro do gatilho não invocam outro gatilho.

Caso de teste


Crie tabela de teste (simplificada, sem linhas irrelevantes):
CREATE TABLE soil_samples (
  pgid SERIAL PRIMARY KEY

 ,utm_zone integer
 ,utm_easting integer
 ,utm_northing integer

 ,wgs84_longitude double precision
 ,wgs84_latitude double precision

 ,yt_albers_geom double precision
);

Acionador fictício para seu primeiro requisito:


Quando uma atualização é feita em utm_zone , utm_easting , ou utm_northing , entãowgs_84_latitude , wgs84_longitude e yt_albers_geom são atualizados por um gatilho.
CREATE OR REPLACE FUNCTION trg_upbef_utm()  RETURNS trigger AS
$func$
BEGIN
   NEW.wgs84_latitude  := NEW.wgs84_latitude + 10;
   NEW.wgs84_longitude := NEW.wgs84_longitude + 10;
   NEW.yt_albers_geom  := NEW.yt_albers_geom + 10;

   RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER upbef_utm
BEFORE UPDATE OF utm_zone, utm_easting, utm_northing ON soil_samples
FOR EACH ROW
WHEN (NEW.utm_zone     IS DISTINCT FROM OLD.utm_zone    OR
      NEW.utm_easting  IS DISTINCT FROM OLD.utm_easting OR
      NEW.utm_northing IS DISTINCT FROM OLD.utm_northing)  -- optional
EXECUTE PROCEDURE trg_upbef_utm();

O WHEN cláusula é opcional. Impede que o gatilho seja acionado quando nenhum valor realmente foi alterado.

Acionador fictício para seu segundo requisito:


Quando uma atualização é feita em wgs84_latitude ou wgs84_longitude , então todos os utm_ campos são atualizados, assim como yt_albers_geom .
CREATE OR REPLACE FUNCTION trg_upbef_wgs84()  RETURNS trigger AS
$func$
BEGIN
   NEW.utm_zone       := NEW.utm_zone + 100;
   NEW.utm_easting    := NEW.utm_easting + 100;
   NEW.utm_northing   := NEW.utm_northing + 100;
   NEW.yt_albers_geom := NEW.yt_albers_geom + 100;

   RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER upbef_wgs84
 BEFORE UPDATE OF wgs84_latitude, wgs84_longitude ON soil_samples
 FOR EACH ROW
 WHEN (NEW.wgs84_latitude  IS DISTINCT FROM OLD.wgs84_latitude OR
       NEW.wgs84_longitude IS DISTINCT FROM OLD.wgs84_longitude)  -- optional
 EXECUTE PROCEDURE trg_upbef_wgs84();

Acione para terceiro requisito nesta linha...

Teste

INSERT INTO soil_samples VALUES (1, 1,1,1, 2,2, 3) RETURNING *;

Acionar upbef_utm :atualização vazia, nada acontece:
UPDATE soil_samples SET utm_zone = 1 RETURNING *;

Atualização com alteração real:o segundo gatilho upbef_wgs84 não será acionado em UPDATE OF utm_zone !
UPDATE soil_samples SET utm_zone = 0 RETURNING *;

Acionar upbef_wgs84 :
UPDATE soil_samples SET wgs84_latitude = 0 RETURNING *;

-> Demonstração do SQLfiddle.