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 本身只是一个包装宏,主要为了语法上的便利, 使消息生成在 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 可用的辅助例程有:

Note

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

还有一个较旧的函数 elog,至今仍被大量使用。 一个 elog 调用:

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

完全等价于:

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

注意,SQLSTATE 错误代码总会取默认值,而且消息字符串不会被翻译。 因此,elog 只应用于内部错误和低层调试日志。 凡是普通用户可能感兴趣的消息,都应通过 ereport。 尽管如此,系统中仍有足够多的内部 不可能发生 错误检查, 因此 elog 依然被广泛使用;对这类消息来说, 由于记法更简洁,它更受青睐。

关于如何编写良好的错误消息,可参见 Section 55.3



[18] 也就是说,是到达 ereport 调用点时的那个值; 辅助报告例程内部对 errno 的更改不会影响它。 如果显式写出 strerror(errno) 作为 errmsg 的参数列表内容,就不是这样了;因此不要这么做。