支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

54.2. 在服务器内报告错误 #

在服务器代码内生成的错误、警告和日志消息应使用 ereport 或其较旧的兄弟 elog 创建。此函数的使用非常复杂,需要一些解释。

每个消息都有两个必需的元素:一个严重级别(从 DEBUGPANIC,定义在 src/include/utils/elog.h 中)和一个主要消息文本。此外,还有可选的元素,其中最常见的是遵循 SQL 规范的 SQLSTATE 约定的错误标识符代码。ereport 本身只是一个 shell 宏,主要为了在 C 源代码中使消息生成看起来像单个函数调用而提供的语法便利。 ereport 直接接受的唯一参数是严重级别。主要消息文本和任何可选的消息元素都是通过调用辅助函数(例如 errmsg)在 ereport 调用中生成的。

一个典型的 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."));

这说明了使用格式代码将运行时值嵌入到消息文本中。此外,还提供了可选的提示消息。辅助函数调用可以以任何顺序编写,但按照惯例,errcodeerrmsg 首先出现。

如果严重级别为 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 来插入 strerrorerrno 的当前值返回的错误消息。[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 是确定需要哪个复数形式的整数值,其余参数根据选定的格式字符串进行格式化。有关更多信息,请参见第 55.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,但支持消息的各种复数形式。有关更多信息,请参见第 55.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,但支持消息的各种复数形式。有关更多信息,请参见第 55.2.2 节

  • errhint(const char *msg, ...) 提供可选的提示消息;当提供有关如何解决问题的建议时,应使用此消息,而不是关于哪里出错的事实细节。消息字符串的处理方式与 errmsg 的处理方式相同。

  • errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...) 类似于 errhint,但支持消息的各种复数形式。有关更多信息,请参见第 55.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) 可以调用以指定在 postmaster 日志中抑制消息的 STATEMENT: 部分。通常,如果消息文本已包含当前语句,则这是合适的。

  • errhidecontext(bool hide_ctx) 可以调用以指定在 postmaster 日志中抑制消息的 CONTEXT: 部分。这应该仅用于详细的调试消息,其中重复包含上下文会使日志过于臃肿。

注意

在一次 ereport 调用中,最多应使用函数 errtableerrtablecolerrtableconstrainterrdatatypeerrdomainconstraint 中的一个。这些函数的存在是为了允许应用程序提取与错误条件关联的数据库对象的名称,而无需检查可能已本地化的错误消息文本。这些函数应该用于应用程序可能希望自动进行错误处理的错误报告。截至 PostgreSQL 9.3,只有 SQLSTATE 类 23(完整性约束违规)中的错误有完整的覆盖范围,但未来可能会扩展。

有一个较旧的函数 elog 仍然被大量使用。一个 elog 调用

elog(level, "format string", ...);

与以下内容完全等效:

ereport(level, errmsg_internal("format string", ...));

请注意,SQLSTATE 错误代码始终是默认的,并且消息字符串不受翻译的影响。因此,elog 应该仅用于内部错误和低级调试日志记录。任何可能引起普通用户兴趣的消息都应该通过 ereport。尽管如此,系统中仍然有足够多的内部不可能发生错误检查,因此 elog 仍然被广泛使用;对于这些消息,由于其符号的简单性,它是首选的。

有关编写良好错误消息的建议,请参见 第 54.3 节



[16] 也就是说,在到达 ereport 调用时生效的值;辅助报告例程中对 errno 的更改不会影响它。如果在 errmsg 的参数列表中显式写入 strerror(errno),则情况并非如此;因此,不要这样做。

提交更正

如果您在文档中看到任何不正确、与您使用特定功能的经验不符或需要进一步澄清的内容,请使用此表格报告文档问题。