服务器代码内部生成的错误、警告和日志消息应使用 ereport
或其旧版本 elog
来创建。该函数的使用足够复杂,需要一些解释。
每条消息都有两个必需的元素:严重性级别(从 DEBUG
到 PANIC
,在 src/include/utils/elog.h
中定义)和主要消息文本。此外,还有可选的元素,其中最常见的是一个错误标识符代码,它遵循 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")));
在 PostgreSQL 12 版本之前,需要额外的括号,但现在它们是可选的。
这是一个更复杂的例子:
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
值返回的错误消息。[18] %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
是决定需要哪种复数形式的整数值,其余参数根据所选格式字符串进行格式化。有关更多信息,请参阅 第 56.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
,但支持消息的各种复数形式。有关更多信息,请参阅 第 56.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
,但支持消息的各种复数形式。有关更多信息,请参阅 第 56.2.2 节。
errhint(const char *msg, ...)
提供一个可选的“提示”消息;当提供解决问题的建议时使用,而不是关于错误发生的事实细节。消息字符串的处理方式与 errmsg
相同。
errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)
类似于 errhint
,但支持消息的各种复数形式。有关更多信息,请参阅 第 56.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
中的一个。这些函数的存在是为了让应用程序能够提取与错误条件相关的数据库对象的名称,而无需检查可能已本地化的错误消息文本。这些函数应在可能需要应用程序进行自动错误处理的错误报告中使用。截至 PostgreSQL 9.3,完整的覆盖仅限于 SQLSTATE 类 23(完整性约束冲突)中的错误,但这可能会在将来扩展。
还有一个较旧的函数 elog
,它仍然被大量使用。一个 elog
调用
elog(level, "format string", ...);
等同于:
ereport(level, errmsg_internal("format string", ...));
请注意,SQLSTATE 错误代码始终是默认值,消息字符串不会被翻译。因此,elog
应仅用于内部错误和低级调试日志记录。任何可能引起普通用户关注的消息都应通过 ereport
处理。尽管如此,系统中仍有大量的内部“不可能发生”错误检查,因此 elog
仍然被广泛使用;由于其记法简单,它更适合用于这些消息。
有关编写良好错误消息的建议,请参阅 第 55.3 节。
[18] 也就是说,到达 ereport
调用时 errno
的值;在辅助报告例程中 errno
的更改不会影响它。如果您在 errmsg
的参数列表中显式写入 strerror(errno)
,则情况并非如此;因此,请勿这样做。
如果您在文档中发现任何不正确、与您对特定功能的实际体验不符或需要进一步阐明的内容,请使用 此表单 报告文档问题。