PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

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

在服务器代码内生成的错误、警告和日志消息应当用 ereport 或其更老的同源函数 elog 创建。 这个函数的使用足够复杂,需要一些解释。

每条消息都有两个必需的元素:一个严重性级别 (从 DEBUG 到 PANIC,定义 在 src/include/utils/elog.h 中)和一段主要 消息文本。 此外还有可选元素,其中最常见的是一个遵循 SQL 规范的 SQLSTATE 约定的错误标识代码。 ereport 本身只是一个外壳宏,它存在的主要 原因是语法上的便利:让消息生成在 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."));

这展示了使用格式代码把运行时值嵌入消息文本的做法。 此外,还提供了一个可选的 “hint” 消息。 辅助函数调用可以按任意顺序书写,但按照惯例 errcode 和 errmsg 出现在最前面。

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

ereport 可用的辅助例程有:

Note

在一次 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 仍然被广泛使用;对这些消息而言,人们 更喜欢它记法的简洁性。

关于如何编写好的错误消息的建议见 Section 55.3。



[12] 即 ereport 调用被到达时 errno 的当前值;辅助报告例程内 errno 的变化不会影响它。 如果您在 errmsg 的参数列表中显式写出 strerror(errno) 就不会有这种性质;因此 不要这样做。