Il contesto dell'operazione (ovvero eliminazione in cascata o eliminazione semplice) deve essere memorizzato da qualche parte. È possibile utilizzare un parametro personalizzato per questo scopo. Quando la cascata eliminare (dalla tabella tbl1
) viene eseguita, trigger vengono lanciati nel seguente ordine:
trigger before delete on tbl1
trigger before delete on tbl2
trigger after delete on tbl1
trigger after delete on tbl2
È necessario quindi due trigger (prima e dopo la cancellazione) sul tavolo tbl1
e un trigger prima di cancellare il tavolo tbl2
.
Creare due trigger su tbl1
. Impostare il parametro personalizzato per on
in funzione prima grilletto e al off
nella funzione grilletto dopo:
create or replace function tbl1_trigger_before_delete()
returns trigger language plpgsql as $$
begin
set tbl1.cascade to on;
return old;
end $$;
create or replace function tbl1_trigger_after_delete()
returns trigger language plpgsql as $$
begin
set tbl1.cascade to off;
return null;
end $$;
create trigger tbl1_trigger_before_delete
before delete on tbl1
for each row execute procedure tbl1_trigger_before_delete();
create trigger tbl1_trigger_after_delete
after delete on tbl1
for each row execute procedure tbl1_trigger_after_delete();
In tbl2
funzione di trigger controllare il valore corrente del parametro. blocco eccezione è necessaria nel caso in cui il parametro non è ancora stata fissata:
create or replace function tbl2_trigger_before_delete()
returns trigger language plpgsql as $$
begin
begin
if current_setting('tbl1.cascade') = 'on' then
raise notice 'cascaded';
else
raise exception '';
end if;
exception when others then
raise notice 'not cascaded';
end;
return old;
end $$;
create trigger tbl2_trigger_before_delete
before delete on tbl2
for each row execute procedure tbl2_trigger_before_delete();
prova:
insert into tbl1 values
(1, '1'),
(2, '2');
insert into tbl2 values
(1, 1, '1'),
(2, 1, '2'),
(3, 2, '3'),
(4, 2, '4');
delete from tbl1 where id = 1;
NOTICE: cascaded
NOTICE: cascaded
DELETE 1
delete from tbl2 where owner = 2;
NOTICE: not cascaded
NOTICE: not cascaded
DELETE 2
soluzione alternativa.
Quando il grilletto prima di cancellare il tavolo tbl2
viene eseguito nel contesto della cascata eliminare, il PG_EXCEPTION_CONTEXT valore diagnostico è impostato su una stringa ed è vuoto quando l'eliminazione non è collegato in cascata:
create or replace function tbl2_trigger_before_delete()
returns trigger language plpgsql as $$
declare
context text;
begin
begin
raise exception '';
exception when others then
GET STACKED DIAGNOSTICS context := PG_EXCEPTION_CONTEXT;
end;
if context = '' then
raise notice 'not cascaded';
else
raise notice 'cascaded';
end if;
return old;
end $$;
create trigger tbl2_trigger_before_delete
before delete on tbl2
for each row execute procedure tbl2_trigger_before_delete();
Questa soluzione può essere discutibile in questo senso che risulta solo dai test, questo comportamento non è documentato da nessuna parte.
Hi klin, il primo la soluzione è "funzionante" ma non era esattamente quello che chiedevo. Forse non ero abbastanza chiaro, ma nel commento di generosità che ho scritto sapevo come risolverlo (usando più trigger), ma volevo sapere se Postgresql _offre questo tipo di informazioni_ (citazione), non potrei memorizzare le informazioni da qualche parte per un uso successivo. Per vostra informazione il secondo tentativo (con 'PG_EXCEPTION_CONTEXT') non funziona sul mio MacOSX con Postgres 9.4, forse è un effetto collaterale del comportamento non documentato che avete notato. – Ciaccia
Capisco. In realtà, ho perso il tuo commento aggiuntivo. Per quanto riguarda la seconda opzione, ho testato anche la soluzione su Postgres 9.4. Sei sicuro di aver testato un trigger ** prima ** cancella? (Trigger dopo l'eliminazione non funziona in questo modo). – klin
Ciao @klin, il mio male, stavo usando un trigger ** dopo ** invece di un ** prima **. Potrei distinguere i due casi senza usare il trucco dell'eccezione, usando semplicemente 'GET DIAGNOSTICS stack = PG_CONTEXT'. Come ho scritto nella mia domanda iniziale, inizialmente ho provato in questo modo ma non è uscito nulla (in realtà a causa del trigger precedente/precedente). Questo è pessimo perché non è documentato da nessuna parte che PG_CONTEXT funzioni solo in un ** prima ** trigger. Inoltre, questo non mi sta aiutando completamente poiché nell'attivazione ** before ** non so ancora se la riga verrà effettivamente cancellata. – Ciaccia