Apakah pg_trigger_depth () buruk untuk digunakan untuk mencegah cascading pemicu (rekursi)?

8

Mengapa pg_trigger_depth() = 0buruk digunakan (untuk apa pun selain debugging) ketika mencegah cascading (rekursi)?

Dapatkah seseorang memberikan kode untuk menunjukkan mengapa itu buruk?

Saya menduga karena jika beberapa pemicu bekerja pada data yang sama pada saat yang sama kondisi yang menghentikan penggunaan pemicu pg_trigger_depth() = 0akan menghentikan pemicu yang berada di urutan kedua untuk melakukan pekerjaan.

Saya pikir ini akan menjadi solusi yang baik untuk pertanyaan (saya) di sini, tetapi saya diberitahu sebaliknya:

Kupikir itu akan menjadi pertanyaan yang bagus.

Ini ditawarkan di sini sebagai solusi:

Dokumentasi Postgres 9.3:

https://www.postgresql.org/docs/9.3/static/functions-info.html

pendaki gunung
sumber

Jawaban:

1

Ya, itu selalu buruk untuk membuat perilaku bergantung pg_trigger_depth()

Mungkin saya sedikit tidak suka dengan pernyataan selimut, tetapi apa manfaatnya? Tidak ada argumen yang bisa saya lihat mengapa Anda menginginkan fitur seperti itu. Tujuan utama dari database adalah untuk memastikan integritas data. Dan sejauh yang saya bisa lihat, dan saya mungkin salah, penggunaan seperti itu selalu merupakan potensi pelanggaran integritas data. Dalam jawaban @ Erwin dia berkata "jika kamu lupa" . Inti dari memastikan integritas adalah untuk menghilangkan kemungkinan itu. Jika agen dapat mengingat semuanya dan memahami konsekuensi dan kode di sekitar mereka, Anda bisa mendapatkan integritas data dari apa pun .

Mari kita perkenalkan beberapa istilah, dalam pemrograman, yang kita miliki

  • "Status" yang mencakup apa pun yang dapat diakses oleh programmer.
  • "konteks eksekusi" yang mencakup lingkungan untuk dieksekusi.

Kami selanjutnya memiliki istilah untuk suatu fungsi, yang tidak memiliki keadaan yang kita sebut fungsi murni ,

Fungsi selalu mengevaluasi nilai hasil yang sama dengan nilai argumen yang sama. Nilai hasil fungsi tidak dapat bergantung pada informasi atau keadaan tersembunyi yang dapat berubah saat eksekusi program berlangsung atau antara eksekusi program yang berbeda, juga tidak dapat bergantung pada input eksternal dari perangkat I / O (biasanya — lihat di bawah).

Perbedaan untuk kemurnian berguna karena menghilangkan beban apapun mengingat apa pun atas nama komputer, atau programmer: f(x) = yadalah selalu benar. Di sini Anda melanggar kemurnian di tempat terburuk - database. Dan, Anda melakukannya dengan cara yang kompleks dan rawan kesalahan - membuat konteks eksekusi internal menjadi hal yang gamblang dalam keadaan aplikasi DB Anda.

Saya tidak mau itu. Pertimbangkan saja kerumitan yang harus Anda lindungi secara mental.

  • Table AIni Trigger Akebakaran
    • Trigger Aselalu mengeluarkan DML Table B, firing Trigger B.
      • Trigger Bbersyarat mengeluarkan DML ke Table A, firing Trigger A.
      • Trigger Bselalu mengeluarkan DML Table A, firing Trigger A.
    • Trigger Abersyarat mengeluarkan DML ke Table B, firing Trigger B.
      • Trigger Bbersyarat mengeluarkan DML ke Table A, firing Trigger A.
      • Trigger Bselalu mengeluarkan DML Table A, firing Trigger A.

Jika itu terlihat rumit, perlu diingat bahwa "kondisional" di sana dapat diperluas lebih lanjut ke "itu terjadi, tetapi mungkin tidak selalu terjadi" , dan "itu tidak terjadi, tetapi itu bisa terjadi di tempat lain."

Agar pg_trigger_depth()bermanfaat, Anda harus memiliki serangkaian acara yang sama rumitnya. Dan, sekarang, Anda ingin eksekusi bergantung pada konten eksekusi di rantai itu?

Saya akan menghindari ini. Jika sistem pemicu Anda adalah kompleks ini, Anda bermain kentang panas dengan granat tangan di lemari sendirian dan sepertinya tidak akan berakhir dengan baik.

Evan Carroll
sumber
10

Hal ini tidak buruk untuk menggunakan per se (IMHO). Anda hanya perlu menyadari implikasinya.

Saya lebih suka membuatnya pg_trigger_depth() < 1daripada pg_trigger_depth() = 0, pada prinsipal, tapi itu tidak penting di sini. Kita berbicara tentang pemicu seperti:

CREATE TRIGGER my_trigger
AFTER INSERT ON my_tbl
FOR EACH ROW
WHEN (pg_trigger_depth() < 1)
EXECUTE PROCEDURE my_trigger_func();

Jika nanti Anda menambahkan pemicu yang pada gilirannya akan memicu pemicu Anda, tidak akan terjadi apa-apa. Pemicu Anda hanya bereaksi terhadap peristiwa yang tidak memicu. Tergantung pada pengaturan Anda, ini mungkin persis apa yang Anda inginkan - atau semacam jebakan, jika Anda lupa tentang ini dan kemudian menambahkan lebih banyak pemicu yang pada gilirannya (juga) akan memicu pemicu ini. Anda mengubah perilaku default. Pastikan untuk mendokumentasikan ini dengan jelas.

Ketahuilah bahwa pg_trigger_depth()menghitung pemicu apa pun , tidak hanya pemicu yang sama untuk mencegah rekursi, sehingga kondisi mencegah pemicu dari pemicu jika dipanggil dari pemicu lain, juga.
Manual:

level pemicu PostgreSQL saat ini (0 jika tidak dipanggil, secara langsung atau tidak langsung, dari dalam pemicu)

Terkait:

Erwin Brandstetter
sumber