Om en "källa" inte "sänder en identifierare" kommer kolumnen att vara oförändrad. Då kan du inte upptäcka om den aktuella UPDATE
gjordes av samma källa som den senaste eller av en källa som inte ändrade kolumnen alls. Med andra ord:detta fungerar inte korrekt.
Om "källan" kan identifieras av någon sessionsinformationsfunktion kan du arbeta med den. Gilla:
NEW.column = session_user;
Ovillkorligt för varje uppdatering.
Allmän lösning
Jag hittade ett sätt att lösa det ursprungliga problemet. Kolumnen kommer att ställas in på ett standardvärde i alla uppdatera där kolumnen inte uppdateras (inte i SET
lista över UPDATE
).
Nyckelelementet är en utlösare per kolumn introducerad i PostgreSQL 9.0 - en kolumnspecifik utlösare med UPDATE OF
column_name
klausul.
Utlösaren aktiveras bara om minst en av de listade kolumnerna nämns som mål för
UPDATE
kommando.
Det är det enda enkla sättet jag hittade för att särskilja om en kolumn uppdaterades med ett nytt värde som är identiskt med det gamla, kontra inte uppdaterat alls.
Man kunde analysera även texten som returneras av current_query()
. Men det verkar knepigt och opålitligt.
Triggerfunktioner
Jag antar en kolumn col
definierad NOT NULL
.
Steg 1: Ställ in col
till NULL
om oförändrad:
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;
Steg 2: Återgå till gammalt värde. Utlösaren kommer bara att aktiveras om värdet faktiskt uppdaterades (se nedan):
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;
Steg 3: Nu kan vi identifiera den saknade uppdateringen och ställa in ett standardvärde istället:
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;
Triggers
Utlösaren för Steg 2 avfyras per kolumn!
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();
Triggernamn är relevanta, eftersom de avfyras i alfabetisk ordning (alla är BEFORE UPDATE
)!
Proceduren kan förenklas med något som "per-not-column triggers" eller något annat sätt att kontrollera mållistan för en UPDATE
i en trigger. Men jag ser inget handtag för detta.
Om col
kan vara NULL
, använd alla andra "omöjliga" mellanvärden och kontrollera efter NULL
dessutom i triggerfunktion 1:
IF OLD.col IS NOT DISTINCT FROM NEW.col THEN
NEW.col := '#impossible_value#';
END IF;
Anpassa resten därefter.