44.8. Обработка ошибок в PL/Tcl
Tcl-код, содержащийся или вызываемый из функции PL/Tcl, может выдавать ошибку либо выполняя недопустимую операцию, либо генерируя ошибку с помощью команды error
языка Tcl или команды elog
языка PL/Tcl. Такие ошибки могут быть перехвачены в среде Tcl с помощью команды Tcl catch
. Если ошибка не перехватывается, а распространяется выше уровня выполнения функций PL/Tcl, она передаётся в запрос, вызвавший функцию, как ошибка SQL.
И напротив, ошибки СУБД, возникающие внутри команд spi_exec
, spi_prepare
и spi_execp
в среде PL/Tcl, выдаются как ошибки 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
.
С информацией в переменной errorCode
среды PL/Tcl удобно работать, загрузив переменную в массив, чтобы имена полей стали индексами в массиве. Пример такого кода:
if {[catch { spi_exec $sql_command }]} { if {[lindex $::errorCode 0] == "POSTGRES"} { array set errorArray $::errorCode if {$errorArray(condition) == "undefined_table"} { # разобраться с отсутствием таблицы } else { # разобраться с другими типами ошибок SQL } } }
(Двойные двоеточия явно указывают, что переменная errorCode
является глобальной.)