Hvis en "kilde" ikke "sender en identifikator", vil kolonnen være uændret. Så kan du ikke opdage, om den aktuelle UPDATE
blev udført af samme kilde som den sidste eller af en kilde, der slet ikke ændrede kolonnen. Med andre ord:dette fungerer ikke korrekt.
Hvis "kilden" kan identificeres af en sessionsinformationsfunktion, kan du arbejde med den. Ligesom:
NEW.column = session_user;
Ubetinget for hver opdatering.
Generel løsning
Jeg fandt en måde at løse det oprindelige problem på. Kolonnen indstilles til en standardværdi i enhver opdatere hvor kolonnen ikke opdateres (ikke i SET
liste over UPDATE
).
Nøgleelementet er en udløser pr. kolonne introduceret i PostgreSQL 9.0 - en kolonnespecifik trigger ved hjælp af UPDATE OF
column_name
klausul.
Udløseren udløses kun, hvis mindst én af de anførte kolonner er nævnt som mål for UPDATE
kommando.
Det er den eneste enkle måde, jeg fandt på at skelne mellem, om en kolonne blev opdateret med en ny værdi, der er identisk med den gamle, kontra slet ikke opdateret.
Man kunne parse også teksten returneret af current_query()
. Men det virker vanskeligt og upålideligt.
Trigger-funktioner
Jeg antager en kolonne col
defineret NOT NULL
.
Trin 1: Indstil col
til NULL
hvis uændret:
CREATE OR REPLACE FUNCTION trg_tbl_upbef_step1()
RETURNS trigger AS
$func$
BEGIN
IF OLD.col = NEW.col THEN
NEW.col := NULL; -- "impossible" value
END IF;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Trin 2: Vend tilbage til gammel værdi. Trigger vil kun blive aktiveret, hvis værdien rent faktisk blev opdateret (se nedenfor):
CREATE OR REPLACE FUNCTION trg_tbl_upbef_step2()
RETURNS trigger AS
$func$
BEGIN
IF NEW.col IS NULL THEN
NEW.col := OLD.col;
END IF;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Trin 3: Nu kan vi identificere den manglende opdatering og indstille en standardværdi i stedet:
CREATE OR REPLACE FUNCTION trg_tbl_upbef_step3()
RETURNS trigger AS
$func$
BEGIN
IF NEW.col IS NULL THEN
NEW.col := 'default value';
END IF;
RETURN NEW;
END
$func$ LANGUAGE plpgsql;
Udløsere
Udløseren for Trin 2 affyres pr kolonne!
CREATE TRIGGER upbef_step1
BEFORE UPDATE ON tbl
FOR EACH ROW
EXECUTE PROCEDURE trg_tbl_upbef_step1();
CREATE TRIGGER upbef_step2
BEFORE UPDATE OF col ON tbl -- key element!
FOR EACH ROW
EXECUTE PROCEDURE trg_tbl_upbef_step2();
CREATE TRIGGER upbef_step3
BEFORE UPDATE ON tbl
FOR EACH ROW
EXECUTE PROCEDURE trg_tbl_upbef_step3();
Triggernavne er relevante, fordi de affyres i alfabetisk rækkefølge (alle er BEFORE UPDATE
)!
Proceduren kunne forenkles med noget som "per-not-column triggers" eller en anden måde at kontrollere mållisten for en UPDATE
på i en udløser. Men jeg kan ikke se noget håndtag for dette.
Hvis col
kan være NULL
, brug enhver anden "umulig" mellemværdi og tjek for NULL
desuden i triggerfunktion 1:
IF OLD.col IS NOT DISTINCT FROM NEW.col THEN
NEW.col := '#impossible_value#';
END IF;
Tilpas resten i overensstemmelse hermed.