41.8. Обработка ошибок в PL/Tcl#

41.8. Обработка ошибок в PL/Tcl

41.8. Обработка ошибок в PL/Tcl #

Код Tcl внутри или вызываемый из функции PL/Tcl может вызывать ошибку, либо выполняя некорректную операцию, либо генерируя ошибку с помощью команды Tcl error или команды elog PL/Tcl. Такие ошибки могут быть перехвачены в Tcl с помощью команды catch. Если ошибка не перехватывается, но разрешается распространяться до верхнего уровня выполнения функции PL/Tcl, она сообщается как SQL-ошибка в вызывающем запросе функции.

В то же время, ошибки SQL, которые возникают внутри команд PL/Tcl spi_exec, spi_prepare и spi_execp, сообщаются как ошибки 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"} {
            # deal with missing table
        } else {
            # deal with some other type of SQL error
        }
    }
}

(Двойные двоеточия явно указывают, что errorCode - это глобальная переменная).