Los mensajes de error, advertencia y registro generados dentro del código del servidor
deben crearse utilizando ereport, o su primo más antiguo
elog. El uso de esta función es lo suficientemente complejo como para
requerir alguna explicación.
Hay dos elementos obligatorios para cada mensaje: un nivel de severidad (que va desde
DEBUG hasta PANIC, definidos en
src/include/utils/elog.h) y un texto de mensaje principal. Además,
hay elementos opcionales, el más común de los cuales es un código identificador de error
que sigue las convenciones SQLSTATE de la especificación SQL.
ereport en sí es solo una macro de envoltura (shell macro) que existe
principalmente por la conveniencia sintáctica de hacer que la generación de mensajes parezca
una sola llamada a función en el código fuente de C. El único parámetro aceptado directamente
por ereport es el nivel de severidad. El texto del mensaje principal y cualquier
elemento de mensaje opcional se generan llamando a funciones auxiliares, como
errmsg, dentro de la llamada a ereport.
Una llamada típica a ereport podría verse así:
ereport(ERROR,
errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero"));
Esto especifica el nivel de severidad de error ERROR (un error común).
La llamada a errcode especifica el código de error SQLSTATE utilizando una
macro definida en src/include/utils/errcodes.h. La llamada a
errmsg proporciona el texto del mensaje principal.
También verás con frecuencia este estilo más antiguo, con un conjunto adicional de paréntesis que rodean las llamadas a funciones auxiliares:
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
Los paréntesis adicionales eran obligatorios antes de la versión 12 de PostgreSQL, pero ahora son opcionales.
Aquí tienes un ejemplo más complejo:
ereport(ERROR,
errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("function %s is not unique",
func_signature_string(funcname, nargs,
NIL, actual_arg_types)),
errhint("Unable to choose a best candidate function. "
"You might need to add explicit typecasts."));
Esto ilustra el uso de códigos de formato para incrustar valores en tiempo de ejecución en
el texto de un mensaje. Además, se proporciona un mensaje de “sugerencia” (hint) opcional.
Las llamadas a funciones auxiliares se pueden escribir en cualquier orden, pero convencionalmente
errcode y errmsg aparecen primero.
Si el nivel de severidad es ERROR o superior, ereport
cancela la ejecución de la consulta actual y no regresa a quien lo llamó. Si el nivel de
severidad es inferior a ERROR, ereport retorna normalmente.
Las rutinas auxiliares disponibles para ereport son:
errcode(sqlerrcode) especifica el código identificador de error SQLSTATE
para la condición. Si no se llama a esta rutina, el identificador de error por defecto es
ERRCODE_INTERNAL_ERROR cuando el nivel de severidad del error es
ERROR o superior, ERRCODE_WARNING cuando el nivel de
error es WARNING, y de lo contrario (para NOTICE y niveles
inferiores) ERRCODE_SUCCESSFUL_COMPLETION.
Aunque estos valores predeterminados suelen ser convenientes, piensa siempre si son apropiados
antes de omitir la llamada a errcode().
errmsg(const char *msg, ...) especifica el texto del mensaje de error
principal y, posiblemente, los valores en tiempo de ejecución que se van a insertar en él. Las
inserciones se especifican mediante códigos de formato de estilo sprintf.
Además de los códigos de formato estándar aceptados por sprintf, se puede utilizar
el código de formato %m para insertar el mensaje de error devuelto por
strerror para el valor actual de errno.
[18]
%m no requiere ninguna entrada correspondiente en la lista de parámetros para
errmsg. Ten en cuenta que la cadena del mensaje se pasará por
gettext para una posible traducción antes de que se procesen los códigos
de formato.
errmsg_internal(const char *msg, ...) es lo mismo que
errmsg, excepto que la cadena del mensaje no se traducirá ni se incluirá
en el diccionario de mensajes de internacionalización. Esto debe utilizarse para casos de
“no debería ocurrir” (cannot happen) en los que probablemente no valga la pena
dedicar esfuerzos de traducción.
errmsg_plural(const char *fmt_singular, const char *fmt_plural,
unsigned long n, ...) es como errmsg, pero con soporte
para varias formas de plural del mensaje.
fmt_singular es el formato singular en inglés,
fmt_plural es el formato plural en inglés,
n es el valor entero que determina qué forma de plural se necesita,
y los argumentos restantes se formatean de acuerdo con la cadena de formato seleccionada. Para
obtener más información, consulta Section 56.2.2.
errdetail(const char *msg, ...) suministra un mensaje de
“detalle” opcional; esto se debe utilizar cuando hay información adicional que
parece inapropiada colocar en el mensaje principal. La cadena del mensaje se procesa de la misma
manera que para errmsg.
errdetail_internal(const char *msg, ...) es lo mismo que
errdetail, excepto que la cadena del mensaje no se traducirá ni se incluirá
en el diccionario de mensajes de internacionalización. Esto debe utilizarse para mensajes de detalle
en los que no valga la pena dedicar esfuerzos de traducción, por ejemplo, porque son demasiado técnicos
para ser útiles para la mayoría de los usuarios.
errdetail_plural(const char *fmt_singular, const char *fmt_plural,
unsigned long n, ...) es como errdetail, pero con soporte
para varias formas de plural del mensaje. Para obtener más información, consulta
Section 56.2.2.
errdetail_log(const char *msg, ...) es lo mismo que
errdetail excepto que esta cadena va únicamente al registro del servidor,
nunca al cliente. Si se utilizan tanto errdetail (o uno de sus equivalentes anteriores)
como errdetail_log, una cadena va al cliente y la otra al registro. Esto es
útil para detalles de error que son demasiado sensibles para la seguridad o demasiado voluminosos
para incluirlos en el informe enviado al cliente.
errdetail_log_plural(const char *fmt_singular, const char
*fmt_plural, unsigned long n, ...) es como
errdetail_log, pero con soporte para varias formas de plural del mensaje.
Para obtener más información, consulta Section 56.2.2.
errhint(const char *msg, ...) suministra un mensaje de
“sugerencia” (hint) opcional; esto se debe utilizar cuando se ofrecen sugerencias sobre
cómo solucionar el problema, a diferencia de los detalles fácticos sobre lo que salió mal. La cadena
del mensaje se procesa de la misma manera que para errmsg.
errhint_plural(const char *fmt_singular, const char *fmt_plural,
unsigned long n, ...) es como errhint, pero con soporte
para varias formas de plural del mensaje. Para obtener más información, consulta
Section 56.2.2.
errcontext(const char *msg, ...) no se suele llamar directamente
desde el sitio de un mensaje ereport; más bien se utiliza en funciones de
retorno de llamada (callback) de error_context_stack para proporcionar información
sobre el contexto en el que ocurrió un error, como la ubicación actual en una función PL.
La cadena del mensaje se procesa de la misma manera que para errmsg. A diferencia
de las otras funciones auxiliares, esta se puede llamar más de una vez por llamada a
ereport; las cadenas sucesivas así suministradas se concatenan separándolas
con saltos de línea.
errposition(int cursorpos) especifica la ubicación textual de un error
dentro de una cadena de consulta. Actualmente solo es útil para errores detectados en las fases
de análisis léxico y sintáctico del procesamiento de consultas.
errtable(Relation rel) especifica una relación cuyo nombre y nombre de esquema
deben incluirse como campos auxiliares en el reporte de error.
errtablecol(Relation rel, int attnum) especifica una columna cuyo nombre,
nombre de tabla y nombre de esquema deben incluirse como campos auxiliares en el reporte de error.
errtableconstraint(Relation rel, const char *conname) especifica una restricción
de tabla cuyo nombre, nombre de tabla y nombre de esquema deben incluirse como campos auxiliares en el
reporte de error. Los índices deben considerarse restricciones para este propósito, tengan o no una
entrada pg_constraint asociada. Ten cuidado de pasar la relación de montón (heap)
subyacente, no el índice en sí, como rel.
errdatatype(Oid datatypeOid) especifica un tipo de datos cuyo nombre y nombre
de esquema deben incluirse como campos auxiliares en el reporte de error.
errdomainconstraint(Oid datatypeOid, const char *conname) especifica una restricción
de dominio cuyo nombre, nombre de dominio y nombre de esquema deben incluirse como campos auxiliares en
el reporte de error.
errcode_for_file_access() es una función de conveniencia que selecciona un
identificador de error SQLSTATE apropiado para un fallo en una llamada al sistema relacionada con el
acceso a archivos. Utiliza el valor guardado de errno para determinar qué código
de error generar. Por lo general, esto debe usarse en combinación con %m en el texto
del mensaje de error principal.
errcode_for_socket_access() es una función de conveniencia que selecciona un
identificador de error SQLSTATE apropiado para un fallo en una llamada al sistema relacionada con sockets.
errhidestmt(bool hide_stmt) se puede llamar para especificar la supresión de la
porción STATEMENT: de un mensaje en el registro del postmaster. Generalmente esto
es adecuado si el texto del mensaje ya incluye la sentencia actual.
errhidecontext(bool hide_ctx) se puede llamar para especificar la supresión de la
porción CONTEXT: de un mensaje en el registro del postmaster. Esto solo debe usarse
para mensajes de depuración detallados en los que la inclusión repetida del contexto inflaría demasiado
el registro.
Como máximo, se debe utilizar una de las funciones errtable,
errtablecol, errtableconstraint,
errdatatype o errdomainconstraint en una llamada a
ereport. Estas funciones existen para permitir que las aplicaciones extraigan
el nombre de un objeto de base de datos asociado con la condición de error sin tener que examinar
el texto del mensaje de error, que podría estar localizado.
Estas funciones deben utilizarse en los reportes de error para los que es probable que las aplicaciones
deseen tener un manejo automático de errores. A partir de PostgreSQL 9.3,
la cobertura completa existe solo para los errores en la clase SQLSTATE 23 (violación de restricción de
integridad), pero es probable que esto se amplíe en el futuro.
Existe una función más antigua, elog, que todavía se utiliza con frecuencia.
Una llamada a elog:
elog(level, "cadena de formato", ...);
es exactamente equivalente a:
ereport(level, errmsg_internal("cadena de formato", ...));
Ten en cuenta que el código de error SQLSTATE siempre se establece por defecto, y la cadena del mensaje
no está sujeta a traducción. Por lo tanto, elog solo debe usarse para errores
internos y registros de depuración de bajo nivel. Cualquier mensaje que pueda ser de interés para
los usuarios comunes debe pasar por ereport. No obstante, existen suficientes
comprobaciones de errores internos de tipo “no debería ocurrir” (cannot happen) en el
sistema como para que elog se siga utilizando ampliamente; se prefiere para esos
mensajes por su simplicidad de notación.
Puedes encontrar consejos sobre cómo escribir buenos mensajes de error en Section 55.3.
[18]
Es decir, el valor que estaba vigente cuando se alcanzó la llamada a ereport;
los cambios de errno dentro de las rutinas de reporte auxiliares no lo afectarán.
Eso no sería cierto si escribieras strerror(errno) explícitamente en la lista de
parámetros de errmsg; por lo tanto, no lo hagas.