Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16 / 17 / 18

55.2. 服务器内部报告错误 #

服务器代码内部生成的错误、警告和日志消息应使用 ereport 或其旧版本 elog 来创建。该函数的使用足够复杂,需要一些解释。

每条消息都有两个必需的元素:严重性级别(从 DEBUGPANIC,在 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."));

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

如果严重性级别为 ERROR 或更高,ereport 会中止当前查询的执行,并且不会返回到调用者。如果严重性级别低于 ERRORereport 会正常返回。

可用的 ereport 辅助例程是:

注意

ereport 调用中最多应使用 errtableerrtablecolerrtableconstrainterrdatatypeerrdomainconstraint 中的一个。这些函数的存在是为了让应用程序能够提取与错误条件相关的数据库对象的名称,而无需检查可能已本地化的错误消息文本。这些函数应在可能需要应用程序进行自动错误处理的错误报告中使用。截至 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),则情况并非如此;因此,请勿这样做。