Di Postgres, kita mendapatkan "stack trace" pengecualian menggunakan kode ini:
EXCEPTION WHEN others THEN
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;
Ini berfungsi dengan baik untuk pengecualian "alami", tetapi jika kita menggunakan pengecualian
RAISE EXCEPTION 'This is an error!';
... maka tidak ada jejak tumpukan. Menurut entri milis , ini mungkin disengaja, meskipun saya tidak bisa seumur hidup mencari tahu mengapa. Itu membuat saya ingin mencari cara lain untuk melemparkan pengecualian selain menggunakan RAISE
. Apakah saya hanya melewatkan sesuatu yang jelas? Adakah yang punya trik untuk ini? Apakah ada pengecualian yang bisa membuat Postgres untuk melempar yang berisi string yang saya pilih, sehingga saya tidak hanya akan mendapatkan string saya dalam pesan kesalahan, tetapi jejak stack penuh juga?
Ini contoh lengkapnya:
CREATE OR REPLACE FUNCTION error_test() RETURNS json AS $$
DECLARE
v_error_stack text;
BEGIN
-- Comment this out to see how a "normal" exception will give you the stack trace
RAISE EXCEPTION 'This exception will not get a stack trace';
-- This will give a divide by zero error, complete with stack trace
SELECT 1/0;
-- In case of any exception, wrap it in error object and send it back as json
EXCEPTION WHEN others THEN
-- If the exception we're catching is one that Postgres threw,
-- like a divide by zero error, then this will get the full
-- stack trace of the place where the exception was thrown.
-- However, since we are catching an exception we raised manually
-- using RAISE EXCEPTION, there is no context/stack trace!
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;
RAISE WARNING 'The stack trace of the error is: "%"', v_error_stack;
return to_json(v_error_stack);
END;
$$ LANGUAGE plpgsql;
error_info
? Sepertinya jenis khusus.Jawaban:
Perilaku ini tampaknya dirancang.
Dalam
src/pl/plpgsql/src/pl_exec.c
konteks kesalahan, callback secara eksplisit memeriksa untuk melihat apakah itu dipanggil dalam konteks pernyataan PL / PgSQLRAISE
dan, jika demikian, lewati memancarkan konteks kesalahan:Saya tidak dapat menemukan referensi spesifik mengapa itu terjadi.
Secara internal di server, tumpukan konteks dihasilkan dengan memproses
error_context_stack
, yang merupakan panggilan balik berantai yang menambahkan informasi ke daftar ketika dipanggil.Ketika PL / PgSQL memasuki fungsi itu menambahkan item ke tumpukan panggilan balik konteks kesalahan. Ketika meninggalkan fungsi, ia menghapus item dari tumpukan itu.
Jika fungsi pelaporan kesalahan server PostgreSQL, suka
ereport
atauelog
dipanggil, itu panggilan balik konteks kesalahan. Tetapi dalam PL / PgSQL jika pemberitahuan bahwa itu dipanggil dariRAISE
panggilan baliknya sengaja tidak melakukan apa-apa.Mengingat itu, saya tidak melihat cara untuk mencapai apa yang Anda inginkan tanpa menambal PostgreSQL. Saya menyarankan memposting email ke pgsql-general menanyakan mengapa
RAISE
tidak memberikan konteks kesalahan sekarang karena PL / PgSQL harusGET STACKED DIAGNOSTICS
memanfaatkannya.(BTW, konteks pengecualian bukan jejak stack seperti itu. Ini terlihat seperti satu karena PL / PgSQL menambahkan setiap panggilan fungsi ke stack, tetapi juga digunakan untuk detail lain di server.)
sumber
RAISE
berkurang oleh cek itu. Saya akan menulis kepada mereka.Anda dapat mengatasi batasan ini dan membuat konteks galat memancarkan plpgsql seperti yang diinginkan dengan memanggil fungsi lain yang menimbulkan (peringatan, pemberitahuan, ...) kesalahan untuk Anda.
Saya memposting solusi untuk itu beberapa tahun yang lalu - di salah satu posting pertama saya di sini di dba.SE :
Detail:
Saya memperluas test case yang diposting untuk menunjukkan bahwa ia berfungsi di Postgres 9.3:
SQL Fiddle.
sumber