2015-12-17 16 views
9

'daki bir tetikleyicinin kaynağını belirleme PostgreSQL'te tetikleme yürütme kaynağının kaynağını belirleyebileceğinizi düşünüyor musunuz? en aşağıdaki iki tablo olduğunu varsayalım: tbl2 referanslar bir "AÇIK DELETE CASCADE" ile tbl1Postgresql

CREATE TABLE tbl1 (id bigserial NOT NULL PRIMARY KEY, 
    name text NOT NULL); 
CREATE TABLE tbl2 (id bigserial NOT NULL PRIMARY KEY, 
    owner bigint NOT NULL REFERENCES tbl1(id) ON DELETE CASCADE, 
    prop text NOT NULL); 

.

CREATE FUNCTION test_fn() RETURNS trigger AS $$ 
BEGIN 
    RAISE NOTICE 'test_fn()'; 
    RETURN NULL; 
END; 
$$ LANGUAGE plpgsql; 

CREATE TRIGGER test_delete AFTER DELETE ON tbl2 
    FOR EACH ROW EXECUTE PROCEDURE test_fn(); 

tetikleyici zaman tbl2 bir SIRA silindikten sonra yürütülür, bağımsız bir şekilde, sıra doğrudan veya kaldırılır ise Dahası

, en üst üste silindikten sonra yürütülür tbl2 bir tetikleyici tanımlayalım çağlayan üzerinde. Örneğin sonunda aşağıda her iki ifadeler tetiği yangın: test_fn İçinde

DELETE FROM tbl1 WHERE id = 1; 
DELETE FROM tbl2 WHERE id = 1; 

(), bu iki dava ayırt etmek mümkün mü? Yani Satır neden kaldırıldı anlamaya? Yığını kullanarak (yani GET DIAGNOSTICS stack = PG_CONTEXT ile) nedenini belirlemeye çalıştım ancak hiçbir şey çıkmadı.

Buraya kimse yardım edebilir mi? Çok önceden teşekkürler

cevap

2

İşlemin içeriği (yani, silme veya basit silme) bir yerde saklanmalıdır. Bu amaç için özel bir parametre kullanabilirsiniz. , tetikleyiciler aşağıdaki sırayla ateş edilir gerçekleştirilir (tablodan tbl1 itibaren) silin basamaklı Ne zaman: masanın tbl1 üzerine

trigger before delete on tbl1 
trigger before delete on tbl2 
trigger after delete on tbl1 
trigger after delete on tbl2 

Sen (öncesi ve silme sonra) bu nedenle iki tetikleyiciler ihtiyaç ve bir tetikleyici önce masada tbl2 silme .

tbl1'da iki tetikleyici oluşturun. tetik önce fonksiyonunda on özel parametresini ve sonra tetikleme fonksiyonunda off için:

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(); 

tbl2 tetik fonksiyonu parametrenin mevcut değerini kontrol edin.

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(); 

Testi:

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  

Alternatif bir çözüm parametre henüz yerleştirilmemiş durumda durum blok gereklidir.

tetik önce masada tbl2 üzerinde silmek silme tanı değeri PG_EXCEPTION_CONTEXT bazı dizeye ayarlanır basamaklanmasını bağlamında yürütülür ve sil cascaded değilken o boş: Bu çözüm

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(); 

Bu anlamda sadece testlerden kaynaklandığı sorgulanabilir olabilir, bu davranış herhangi bir yerde belgelenmez.

+1

Merhaba klin, ilk almak için ayrıntılı ile analiz etmek, açıklamak kullanmak gerekir

Çözüm "çalışıyor" ama tam olarak istediğim şey değildi. Belki yeterince açık değildim, ama yazdığım kelle yorumunda bunu nasıl çözeceğimi biliyordum (birden çok tetikleyici kullanarak), ama Postgresql'in bu türden bir bilgi olup olmadığını bilmek istedim (alıntı), bilgiyi bir yerde saklayamazdım Daha sonra kullanmak için. Bilgileriniz için (PG_EXCEPTION_CONTEXT ile) ikinci denemem MacOSX'umda Postgres 9.4'ü çalıştırıyor, belki de sizin fark ettiğiniz belgelenmiş davranışların yan etkisidir. – Ciaccia

+0

Anladım. Aslında ek yorumlarınızı kaçırdım. İkinci seçenek olarak, çözümü Postgres 9.4'te de test ettim. ** önce bir tetiği test ettiğinden emin misin? (Silme sonrasında tetikleme böyle bir şekilde çalışmaz). – klin

+0

Merhaba Klin, kötüyüm, ** öncesi ** yerine ** sonra ** trigger kullanıyordum. İki durumu istisna trickini kullanarak ayırt edebilirim, sadece 'GET DIAGNOSTICS stack = PG_CONTEXT' kullanarak. Orijinal sorumu yazdığım gibi, başlangıçta bu şekilde denedim ama hiçbir şey çıkmadı (aslında tetikleme sonrası/öncesi). Bu, PG_CONTEXT'nin sadece bir ** öncesi ** tetikleyicide çalıştığı herhangi bir yerde belgelenmediği için çok kötü. Dahası, bu bana tamamen yardımcı olmuyor çünkü ** öncesi ** tetikleyici hala satırın gerçekten silinip silinmeyeceğinden emin değilim. – Ciaccia

1

PostgreSQL sorgu analizcisinden çıkan sonuçları görmek için EXPLAIN ANALYZE'ı sorguda denediniz mi? PostgreSQL v9'a göre.4 belge, Postgres gösterecektir

"EXPLAIN ANALYZE tarafından gösterilen yürütme süresi, yürütme başlatma ve kapama zamanının yanı sıra tetiklenen herhangi bir tetikleyiciyi çalıştırma süresini de içerir, ancak ayrıştırma, yeniden yazma işlemini içermez ya da planlama zamanı.Önceki Tetikleyicileri yürütme için harcanan süre, ilgili Ek, Güncelleştirme veya Silme düğümü için zamana dahil edilir, ancak AFTER tetikleyicileri yürütme için harcanan süre orada sayılmaz çünkü AFTER tetikleyicileri tamamlandıktan sonra tetiklenir Her tetikleyicide harcanan toplam süre (ÖNCE veya SONRA) ayrıca gösterilir. Ertelenmiş kısıtlama tetikleyicilerinin işlemin sonuna kadar icra edilmeyeceğini ve bu nedenle EXPLAIN ANALYZE tarafından hiç dikkate alınmadığını unutmayın.

(kaynak URL: http://www.postgresql.org/docs/9.4/static/using-explain.html) PostgreSQL v9.1 kullanıyorsanız, ancak, aynı işlevselliği (http://www.postgresql.org/docs/9.1/static/sql-explain.html)