56.2. 在服务器内报告错误#
应使用ereport
或其较早的同类项elog
创建服务器代码内生成的错误、警告和日志消息。此函数的使用非常复杂,需要一些解释。
每个消息都有两个必需元素:严重性级别(范围从DEBUG
到PANIC
)和一个主消息文本。此外,还有可选元素,最常见的是遵循 SQL 规范的 SQLSTATE 约定的错误标识符代码。ereport
本身只是一个 shell 宏,主要用于语法方便,使消息生成看起来像 C 源代码中的单个函数调用。ereport
直接接受的唯一参数是严重性级别。主消息文本和任何可选消息元素都是通过在ereport
调用中调用辅助函数(例如errmsg
)生成的。
对ereport
的典型调用可能如下所示
ereport(ERROR,
errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero"));
这指定了错误严重性级别ERROR
(一个普通的错误)。errcode
调用使用在src/include/utils/errcodes.h
中定义的宏指定 SQLSTATE 错误代码。errmsg
调用提供主消息文本。
您还经常会看到这种旧样式,其中辅助函数调用周围有一组额外的括号
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
在PostgreSQL12 版本之前需要额外的括号,但现在是可选的。
这是一个更复杂的示例
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."));
这说明了如何使用格式代码将运行时值嵌入到消息文本中。此外,还提供了可选的“提示”消息。辅助函数调用可以按任何顺序编写,但通常errcode
和errmsg
首先出现。
如果严重性级别为ERROR
或更高,则ereport
会中止当前查询的执行,并且不会返回给调用者。如果严重性级别低于ERROR
,则ereport
会正常返回。
用于ereport
的可用辅助例程是
errcode(sqlerrcode)
为该条件指定 SQLSTATE 错误标识符代码。如果未调用此例程,当错误严重性级别为ERROR
或更高时,错误标识符默认为ERRCODE_INTERNAL_ERROR
,当错误级别为WARNING
时,默认为ERRCODE_WARNING
,否则(对于NOTICE
及以下)默认为ERRCODE_SUCCESSFUL_COMPLETION
。虽然这些默认值通常很方便,但在省略errcode()
调用之前,请始终考虑它们是否合适。errmsg(const char *msg, ...)
指定主要错误消息文本,以及可能要插入其中的运行时值。插入内容由sprintf
样式的格式代码指定。除了sprintf
接受的标准格式代码外,还可以使用格式代码%m
来插入strerror
为errno
的当前值返回的错误消息。 [16]%m
不需要在errmsg
的参数列表中具有任何对应的条目。请注意,在处理格式代码之前,消息字符串将通过gettext
进行处理,以进行可能的本地化。errmsg_internal(const char *msg, ...)
与errmsg
相同,但消息字符串不会被翻译,也不会包含在国际化消息词典中。这应该用于 “不可能发生” 的情况,这些情况可能不值得花费翻译精力。errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)
类似于errmsg
,但支持消息的各种复数形式。fmt_singular
是英语单数格式,fmt_plural
是英语复数格式,n
是确定需要哪种复数形式的整数值,其余参数根据选定的格式字符串进行格式化。有关更多信息,请参见 第 57.2.2 节。errdetail(const char *msg, ...)
提供可选的 “详细信息” 消息;当有其他信息不适合放入主要消息中时,应使用此消息。消息字符串的处理方式与errmsg
的处理方式完全相同。errdetail_internal(const char *msg, ...)
与errdetail
相同,但消息字符串不会被翻译,也不会包含在国际化消息词典中。这应该用于不值得花费翻译精力的详细信息消息,例如因为它们过于技术性而对大多数用户没有用处。errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)
类似于errdetail
,但支持消息的各种复数形式。有关更多信息,请参见 第 57.2.2 节。errdetail_log(const char *msg, ...)
与errdetail
相同,但此字符串仅发送到服务器日志,绝不会发送到客户端。如果同时使用了errdetail
(或其上述等效项之一)和errdetail_log
,则一个字符串将发送到客户端,另一个字符串将发送到日志。这对于过于敏感或过于庞大而无法包含在发送给客户端的报告中的错误详细信息非常有用。errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)
类似于errdetail_log
,但支持消息的各种复数形式。有关更多信息,请参见 第 57.2.2 节。errhint(const char *msg, ...)
提供可选的 “提示” 消息;当提供有关如何解决问题而不是有关出错事实的建议时,应使用此消息。消息字符串的处理方式与errmsg
的处理方式完全相同。errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)
与errhint
类似,但支持消息的各种复数形式。有关详细信息,请参阅 第 57.2.2 节。errcontext(const char *msg, ...)
通常不会直接从ereport
消息站点调用;而是在error_context_stack
回调函数中使用,以提供有关错误发生时的上下文的信息,例如 PL 函数中的当前位置。消息字符串的处理方式与errmsg
完全相同。与其他辅助函数不同,它可以针对每个ereport
调用调用多次;因此,连续提供的字符串会连接起来,并用换行符分隔。errposition(int cursorpos)
指定查询字符串中错误的文本位置。目前,它仅对在查询处理的词法和语法分析阶段检测到的错误有用。errtable(Relation rel)
指定一个关系,其名称和模式名称应作为辅助字段包含在错误报告中。errtablecol(Relation rel, int attnum)
指定一个列,其名称、表名称和模式名称应作为辅助字段包含在错误报告中。errtableconstraint(Relation rel, const char *conname)
指定一个表约束,其名称、表名称和模式名称应作为辅助字段包含在错误报告中。对于此目的,索引应被视为约束,无论它们是否具有关联的pg_constraint
条目。请务必传递基础堆关系,而不是索引本身,作为rel
。errdatatype(Oid datatypeOid)
指定一个数据类型,其名称和模式名称应作为辅助字段包含在错误报告中。errdomainconstraint(Oid datatypeOid, const char *conname)
指定一个域约束,其名称、域名称和模式名称应作为辅助字段包含在错误报告中。errcode_for_file_access()
是一个便捷函数,用于为文件访问相关系统调用中的故障选择适当的 SQLSTATE 错误标识符。它使用已保存的errno
来确定要生成的错误代码。通常,这应与主错误消息文本中的%m
结合使用。errcode_for_socket_access()
是一个便利函数,它为套接字相关系统调用的故障选择一个合适的 SQLSTATE 错误标识符。errhidestmt(bool hide_stmt)
可用于指定禁止在邮政局长日志中显示消息的STATEMENT:
部分。通常,如果消息文本已经包含当前语句,则这样做是合适的。errhidecontext(bool hide_ctx)
可用于指定禁止在邮政局长日志中显示消息的CONTEXT:
部分。这仅应用于冗长的调试消息,其中重复包含上下文会使日志过大。
注意
在ereport
调用中最多只能使用一个函数errtable
、errtablecol
、errtableconstraint
、errdatatype
或errdomainconstraint
。这些函数的存在是为了允许应用程序提取与错误条件关联的数据库对象的名称,而无需检查可能已本地化的错误消息文本。这些函数应用于错误报告,对于这些报告,应用程序可能希望自动处理错误。从PostgreSQL9.3 开始,仅对 SQLSTATE 类 23(完整性约束冲突)中的错误提供了完整覆盖,但将来可能会扩展此范围。
有一个较旧的函数elog
,它仍然被大量使用。一个elog
调用
elog(level, "format string", ...);
与以下内容完全等效
ereport(level, errmsg_internal("format string", ...));
请注意,SQLSTATE 错误代码始终为默认值,并且消息字符串不会翻译。因此,elog
应仅用于内部错误和低级调试日志记录。任何可能对普通用户感兴趣的消息都应通过ereport
传递。尽管如此,系统中仍有足够的内部“不可能发生”错误检查,因此elog
仍然被广泛使用;对于那些消息,它因其符号简单而受到青睐。
有关编写良好错误消息的建议,请参见第 56.3 节。
[16]也就是说,当ereport
调用被访问时当前的值;辅助报告例程中errno
的更改不会影响它。如果您要在errmsg
的参数列表中显式编写strerror(errno)
,则情况并非如此;因此,请不要这样做。