En Postgres, obtenemos el "seguimiento de la pila" de excepciones usando este código:
EXCEPTION WHEN others THEN
GET STACKED DIAGNOSTICS v_error_stack = PG_EXCEPTION_CONTEXT;
Esto funciona bien para excepciones "naturales", pero si planteamos una excepción usando
RAISE EXCEPTION 'This is an error!';
... entonces no hay rastro de pila. De acuerdo con una entrada de la lista de correo , esto podría ser intencional, aunque por mi vida no puedo entender por qué. Me dan ganas de encontrar otra forma de lanzar una excepción que no sea usar RAISE
. ¿Me estoy perdiendo algo obvio? ¿Alguien tiene un truco para esto? ¿Hay una excepción que pueda hacer que Postgres lance que contenga una cadena de mi elección, de modo que obtenga no solo mi cadena en el mensaje de error, sino también el seguimiento completo de la pila?
Aquí hay un ejemplo completo:
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
? Parece un tipo personalizado.Respuestas:
Este comportamiento parece ser por diseño.
En
src/pl/plpgsql/src/pl_exec.c
el contexto de error, la devolución de llamada verifica explícitamente si se está llamando en el contexto de unaRAISE
instrucción PL / PgSQL y, de ser así, omite la emisión del contexto de error:No puedo encontrar ninguna referencia específica de por qué ese es el caso.
Internamente en el servidor, la pila de contexto se genera procesando el
error_context_stack
, que es una devolución de llamada encadenada que agrega información a una lista cuando se llama.Cuando PL / PgSQL ingresa una función, agrega un elemento a la pila de devolución de llamada de contexto de error. Cuando deja una función, elimina un elemento de esa pila.
Si las funciones de informe de errores del servidor PostgreSQL, como
ereport
oelog
se llaman, llama a la devolución de llamada de contexto de error. Pero en PL / PgSQL si se da cuenta de que se está llamando desdeRAISE
sus devoluciones de llamada intencionalmente no hace nada.Dado eso, no veo ninguna manera de lograr lo que quieres sin parchear PostgreSQL. Sugiero publicar el correo en pgsql-general preguntando por qué
RAISE
no proporciona el contexto de error ahora que PL / PgSQL tieneGET STACKED DIAGNOSTICS
que usarlo.(Por cierto, el contexto de excepción no es un seguimiento de la pila como tal. Se parece un poco a uno porque PL / PgSQL agrega cada llamada de función a la pila, pero también se usa para otros detalles en el servidor).
fuente
RAISE
ve disminuida por ese control. Les escribiré a ellos.Puede evitar esta restricción y hacer que plpgsql emita un contexto de error según lo desee llamando a otra función que genera (advertencia, aviso, ...) el error por usted.
Publiqué una solución para eso hace un par de años, en una de mis primeras publicaciones aquí en dba .
Detalles:
Expandí su caso de prueba publicado para demostrar que funciona en Postgres 9.3:
SQL Fiddle.
fuente