W Postgres otrzymujemy „ślad stosu” wyjątków za pomocą tego kodu:
EXCEPTION WHEN others THEN
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;
Działa to dobrze w przypadku „naturalnych” wyjątków, ale jeśli zgłaszamy wyjątek za pomocą
RAISE EXCEPTION 'This is an error!';
... wtedy nie ma śladu stosu. Zgodnie z wpisem na liście mailowej może to być celowe, chociaż nie mogę przez całe życie dowiedzieć się, dlaczego. To sprawia, że chcę wymyślić inny sposób zgłoszenia wyjątku niż użycie RAISE
. Czy brakuje mi czegoś oczywistego? Czy ktoś ma na to jakiś sposób? Czy istnieje wyjątek, który mogę skłonić Postgres do rzucenia, który zawierałby wybrany przeze mnie ciąg, tak że dostałbym nie tylko mój ciąg w komunikacie o błędzie, ale także ślad pełnego stosu?
Oto pełny przykład:
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
? Wygląda na typ niestandardowy.Odpowiedzi:
To zachowanie wydaje się zgodne z projektem.
W
src/pl/plpgsql/src/pl_exec.c
kontekście błędu wywołanie zwrotne wyraźnie sprawdza, czy jest wywoływane w kontekścieRAISE
instrukcji PL / PgSQL , a jeśli tak, pomija emitowanie kontekstu błędu:Nie mogę znaleźć żadnego konkretnego odniesienia do tego , dlaczego tak jest.
Wewnętrznie na serwerze stos kontekstowy jest generowany przez przetwarzanie
error_context_stack
, który jest połączeniem zwrotnym z łańcuchem, który dodaje informacje do listy po wywołaniu.Gdy PL / PgSQL wchodzi w funkcję, dodaje element do stosu wywołania zwrotnego kontekstu błędu. Kiedy opuszcza funkcję, usuwa przedmiot ze stosu.
Jeśli funkcje raportowania błędów serwera PostgreSQL, takie jak
ereport
lubelog
są wywoływane, wywołuje wywołanie zwrotne kontekstu błędu. Ale w PL / PgSQL, jeśli zauważy, że jest wywoływany przezRAISE
wywołania zwrotne celowo nie rób nic.Biorąc to pod uwagę, nie widzę żadnego sposobu na osiągnięcie tego, co chcesz bez łatania PostgreSQL. Sugeruję wysyłanie wiadomości do pgsql-general z pytaniem, dlaczego
RAISE
nie udostępnia kontekstu błędu, skoro PL / PgSQL musiGET STACKED DIAGNOSTICS
z niego skorzystać.(BTW, kontekst wyjątku nie jest śladem stosu jako takim. Wygląda trochę jak jeden, ponieważ PL / PgSQL dodaje każde wywołanie funkcji do stosu, ale jest również używane do innych szczegółów na serwerze.)
źródło
RAISE
kontrola zmniejsza użyteczność . Napiszę do nich.Możesz obejść to ograniczenie i sprawić, aby plpgsql emitował kontekst błędu zgodnie z potrzebami, wywołując inną funkcję, która podnosi (ostrzeżenie, zawiadomienie, ...) błąd za Ciebie.
Rozwiązałem to kilka lat temu - w jednym z moich pierwszych postów tutaj na dba.SE :
Detale:
Rozszerzyłem opublikowany przypadek testowy, aby wykazać, że działa on w Postgres 9.3:
SQL Fiddle.
źródło