55.2. Вывод сообщений об ошибках в коде сервера #

Сообщения об ошибках, предупреждения и обычные сообщения, выдаваемые в коде сервера должны создаваться функцией ereport или родственной её предшественницей elog. Использование этой функции достаточно сложно и требует дополнительного объяснения.

У каждого сообщения есть два обязательных элемента: уровень важности (от DEBUG до PANIC, которые определены в файле src/include/utils/elog.h) и основной текст сообщения. В дополнение к ним есть необязательные элементы, из которых часто используется код идентификатора ошибки, соответствующий определению SQLSTATE в спецификации SQL. Макрос ereport сам по себе является просто оболочкой, которая существует в основном для синтаксического удобства, чтобы выдача сообщения выглядела как вызов одной функции в коде C. Единственный параметр, который принимает непосредственно ereport, — это уровень важности. Основной текст и любые дополнительные элементы сообщения генерируются в вызове ereport в результате использования вспомогательных функций, таких как errmsg.

Типичный вызов ereport выглядит примерно так:

ereport(ERROR,
        errcode(ERRCODE_DIVISION_BY_ZERO),
        errmsg("division by zero"));

В нём задаётся уровень важности ERROR (заурядная ошибка). В вызове errcode указывается код ошибки SQLSTATE по макросу, определённому в src/include/utils/errcodes.h. Вызов 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."));

В нём демонстрируется использование кодов форматирования для включения значений времени выполнения в текст сообщения. Также в нём добавляется дополнительное сообщение «подсказки». Вызовы вспомогательных функций можно записывать в любом порядке, но обычно сначала вызываются errcode и errmsg.

При уровне важности ERROR или более высоком, ereport прерывает выполнение текущего запроса и не возвращает управление в вызывающий код. Если уровень важности ниже ERROR, ereport завершается обычным образом.

Для ereport предлагаются следующие вспомогательные функции:

Примечание

В вызове 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; для таких сообщений эта функция предпочитается из-за простоты записи.

Советы по написанию хороших сообщений об ошибках можно найти в Разделе 55.3.



[16] То есть значение, которое было текущим, когда была вызвана ereport; изменения errno во вспомогательных функциях выдачи сообщений на него не повлияют. Это будет не так, если вы запишете strerror(errno) явно в списке параметров errmsg; поэтому делать так не нужно.