Pokud „zdroj“ neposílá identifikátor, sloupec se nezmění. Pak nemůžete zjistit, zda je aktuální UPDATE
bylo provedeno stejným zdrojem jako poslední nebo zdrojem, který sloupec vůbec nezměnil. Jinými slovy:toto nefunguje správně.
Pokud je „zdroj“ identifikovatelný pomocí jakékoli funkce informací o relaci, můžete s tím pracovat. Jako:
NEW.column = session_user;
Bezpodmínečně pro každou aktualizaci.
Obecné řešení
Našel jsem způsob, jak vyřešit původní problém. Sloupec bude nastaven na výchozí hodnotu libovolné aktualizovat, kde sloupec není aktualizován (nikoli v SET
seznam UPDATE
).
Klíčovým prvkem je spouštěč pro každý sloupec představen v PostgreSQL 9.0 – spouštěč specifický pro sloupec pomocí UPDATE OF
column_name
doložka.
Spouštěč se spustí, pouze pokud je alespoň jeden z uvedených sloupců uveden jako cíl
UPDATE
příkaz.
To je jediný jednoduchý způsob, jak jsem našel, jak rozlišit, zda byl sloupec aktualizován novou hodnotou shodnou se starou, nebo zda nebyl aktualizován vůbec.
Jeden mohl také analyzovat text vrácený current_query()
. Ale to se zdá být složité a nespolehlivé.
Spouštěcí funkce
Předpokládám sloupec col
definováno NOT NULL
.
Krok 1: Nastavte col
na NULL
pokud se nezmění:
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;
Krok 2: Vrátit se na starou hodnotu. Spouštěč se spustí pouze v případě, že byla hodnota skutečně aktualizována (viz níže):
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;
Krok 3: Nyní můžeme identifikovat chybějící aktualizaci a místo toho nastavit výchozí hodnotu:
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;
Spouštěče
Spouštěč pro Krok 2 se spouští za sloupec!
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();
Názvy spouštěčů jsou relevantní, protože jsou spouštěny v abecedním pořadí (vše BEFORE UPDATE
)!
Postup by mohl být zjednodušen pomocí něčeho jako "spouštěče pro jednotlivé sloupce" nebo jakýmkoli jiným způsobem, jak zkontrolovat seznam cílů UPDATE
ve spoušti. Ale nevidím pro to žádné řešení.
Pokud col
může být NULL
, použijte jakoukoli jinou "nemožnou" mezihodnotu a zkontrolujte NULL
navíc ve funkci spouštění 1:
IF OLD.col IS NOT DISTINCT FROM NEW.col THEN
NEW.col := '#impossible_value#';
END IF;
Zbytek tomu přizpůsobte.