44.8. PL/Tcl 中的错误处理 #
PL/Tcl 函数内的 Tcl 代码,或从 PL/Tcl 函数调用的 Tcl 代码,都可能引发错误:要么是执行了某个非法操作,要么是通过 Tcl 的 error 命令或 PL/Tcl 的 elog 命令主动生成错误。在 Tcl 中,可以使用 catch 命令捕获这类错误。如果错误没有被捕获,而是一路传播到 PL/Tcl 函数执行的顶层,那么它就会在调用该函数的查询中作为 SQL 错误报告出来。
反过来,在 PL/Tcl 的 spi_exec、spi_prepare 和 spi_execp 命令中发生的 SQL 错误会作为 Tcl 错误报告,因此也可以被 Tcl 的 catch 命令捕获。(这些 PL/Tcl 命令中的每一个都会在子事务中运行其 SQL 操作,该子事务在出错时会回滚,因此任何部分完成的操作都会自动清理掉。)同样地,如果某个错误在未被捕获的情况下传播到顶层,它又会重新变成 SQL 错误。
Tcl 提供了一个 errorCode 变量,它以便于 Tcl 程序解释的形式携带关于错误的附加信息。该变量的内容采用 Tcl 列表格式,第一个词标识报告该错误的子系统或库;其后的内容则由相应子系统或库自行定义。对于由 PL/Tcl 命令报告的数据库错误,第一个词是 POSTGRES,第二个词是 PostgreSQL 版本号,后续内容则是字段名/字段值对,用来提供关于该错误的详细信息。字段 SQLSTATE、condition 和 message 总是会提供(前两个分别对应附录 A 中所示的错误代码和条件名称)。可能出现的字段包括
detail、hint、context、schema、table、column、datatype、constraint、statement、cursor_position、filename、lineno 以及
funcname。
处理 PL/Tcl 的 errorCode 信息时,一种方便的办法是把它载入数组中,这样字段名就变成了数组下标。对应的代码可能如下所示:
if {[catch { spi_exec $sql_command }]} {
if {[lindex $::errorCode 0] == "POSTGRES"} {
array set errorArray $::errorCode
if {$errorArray(condition) == "undefined_table"} {
# 处理表不存在的情况
} else {
# 处理其他类型的 SQL 错误
}
}
}
(双冒号显式指定 errorCode 是一个全局变量。)
报告文档问题
阅读 上游文档. 通过 PostgreSQL 文档反馈表单.