Без кейворда
Сообщения об ошибках, предупреждения и обычные сообщения, выдаваемые в коде сервера должны создаваться функцией ereport или родственной её предшественницей elog . Использование этой функции достаточно сложно и требует дополнительного объяснения.
У каждого сообщения есть два обязательных элемента: уровень важности (от DEBUG до PANIC ) и основной текст сообщения. В дополнение к ним есть необязательные элементы, из которых часто используется код идентификатора ошибки, соответствующий определению SQLSTATE в спецификации SQL. Функция ereport сама по себе является просто оболочкой, которая существует в основном для синтаксического удобства, чтобы выдача сообщения выглядела как вызов функции в коде C. Единственный параметр, который принимает непосредственно функция ereport , это уровень важности. Основной текст и любые дополнительные элементы сообщения генерируются в результате вызова вспомогательных функций, таких как errmsg , в вызове ereport .
Типичный вызов ereport выглядит примерно так:
В нём задаётся уровень важности ERROR (заурядная ошибка). В вызове errcode указывается код ошибки SQLSTATE по макросу, определённому в src/include/utils/errcodes.h . Вызов errmsg даёт текст основного сообщения. Обратите внимание на дополнительный набор скобок, окружающих вызовы вспомогательных функций — они загромождают код, но требуются синтаксисом.
Более сложный пример:
В нём демонстрируется использование кодов форматирования для включения значений времени выполнения в текст сообщения. Также в нём добавляется дополнительное сообщение « подсказки » .
При уровне важности ERROR или более высоком, ereport прерывает выполнение пользовательской функции и не возвращает управление в вызывающий код. Если уровень важности ниже ERROR , ereport завершается обычным способом.
Для ereport предлагаются следующие вспомогательные функции:
errcode(sqlerrcode) задаёт код идентификатора ошибки SQLSTATE для данной ошибки. Если эта функция не вызывается, подразумевается идентификатор ошибки ERRCODE_INTERNAL_ERROR при уровне важности ERROR или выше, либо ERRCODE_WARNING при уровне важности WARNING , иначе (при уровне NOTICE или ниже) — ERRCODE_SUCCESSFUL_COMPLETION . Хотя эти значения по умолчанию довольно разумны, всегда стоит подумать, насколько они уместны, прежде чем опустить вызов errcode() .
errmsg(const char *msg, . ) задаёт основной текст сообщения об ошибке и, возможно, значения времени выполнения, которые будут в него включаться. Эти включения записываются кодами формата в стиле sprintf . В дополнение к стандартным кодам формата, принимаемым функцией sprintf , можно использовать код формата %m , который вставит сообщение об ошибке, возвращённое строкой strerror для текущего значения errno . [13] Для %m не требуется соответствующая запись в списке параметров errmsg . Заметьте, что эта строка будет пропущена через gettext , то есть может быть локализована, до обработки кодов формата.
errmsg_internal(const char *msg, . ) действует как errmsg , но её строка сообщения не будет переводиться и включаться в словарь сообщений для интернационализации. Это следует использовать для случаев, которые « не происходят никогда » , так что тратить силы на их перевод не стоит.
errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, . ) действует подобно errmsg , но поддерживает различные формы сообщения с множественными числами. Параметр fmt_singular задаёт строку формата на английском для единственного числа, fmt_plural — формат для множественного числа, n задаёт целое число, определяющее, какая именно форма множественного числа требуется, а остальные аргументы форматируются согласно выбранной строке формата. За дополнительными сведениями обратитесь к Подразделу 52.2.2.
errdetail(const char *msg, . ) задаёт дополнительное « подробное » сообщение; оно должно использоваться, когда есть дополнительная информация, которую неуместно включать в основное сообщение. Строка сообщения обрабатывается так же, как и для errmsg .
errdetail_internal(const char *msg, . ) действует как errdetail , но её строка сообщения не будет переводиться и включаться в словарь сообщений для интернационализации. Это следует использовать для подробных сообщений, на перевод которых не стоит тратить силы, например, когда это техническая информация, непонятная большинству пользователей.
errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, . ) действует подобно errdetail , но поддерживает различные формы сообщения с множественными числами. За дополнительными сведениями обратитесь к Подразделу 52.2.2.
errdetail_log(const char *msg, . ) подобна errdetail , но выводимая строка попадает только в журнал сервера, и никогда не передаётся клиенту. Если используется и errdetail (или один из её эквивалентов), и errdetail_log , тогда одна строка передаётся клиенту, а другая отправляется в журнал. Это полезно для вывода подробных сообщений, имеющих конфиденциальный характер или большой размер, так что передавать их клиенту нежелательно.
errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, . ) действует подобно errdetail_log , но поддерживает различные формы сообщения с множественными числами. За дополнительными сведениями обратитесь к Подразделу 52.2.2.
errhint(const char *msg, . ) передаёт дополнительное сообщение « подсказки » ; это позволяет предложить решение проблемы, а не просто сообщить факты, связанные с ней. Строка сообщения обрабатывается так же, как и для errmsg .
errcontext(const char *msg, . ) обычно не вызывается непосредственно с места вызова ereport , а используется в функциях обратного вызова error_context_stack и выдаёт информацию о контексте, в котором произошла ошибка, например, о текущем положении в функции PL. Строка сообщения обрабатывается так же, как и для errmsg . В отличие от других вспомогательных функций, внутри вызова ereport её можно вызывать неоднократно; добавляемые таким образом последовательные сообщения складываются через символы перевода строк.
errposition(int cursorpos) задаёт положение ошибки в тексте запроса. В настоящее время это полезно только для ошибок, выявляемых на этапах лексического и синтаксического анализа запроса.
errtable(Relation rel) определяет отношение, имя и схема которого должны быть включены во вспомогательные поля сообщения об ошибке.
errtablecol(Relation rel, int attnum) определяет столбец, имя которого, вместе с именем таблицы и схемы, должно быть включено во вспомогательные поля сообщения об ошибке.
errtableconstraint(Relation rel, const char *conname) задаёт имя ограничения таблицы, которое вместе с именем таблицы и схемы должно быть включено во вспомогательные поля сообщения об ошибке. В данном контексте индекс считается ограничением, независимо от того, имеется ли для него запись в pg_constraint . Заметьте, что при этом в качестве rel нужно передавать нижележащее отношение, а не сам индекс.
errdatatype(Oid datatypeOid) задаёт тип данных, имя которого, вместе с именем схемы, должно включаться во вспомогательные поля сообщения об ошибке.
errdomainconstraint(Oid datatypeOid, const char *conname) задаёт имя ограничения домена, которое вместе с именем домена и схемы должно включаться во вспомогательные поля сообщения об ошибке.
errcode_for_file_access() — вспомогательная функция, выбирающая подходящий идентификатор SQLSTATE при сбое в системном вызове, в котором происходит обращение к файловой системе. Какой код ошибки генерировать, она определяет по сохранённому значению errno . Обычно это используется в сочетании с %m в основном сообщении об ошибке.
errcode_for_socket_access() — вспомогательная функция, выбирающая подходящий идентификатор SQLSTATE при сбое в системном вызове, в котором происходит обращение к сокетам.
ПримечаниеВ вызове ereport следует использовать максимум одну из функций errtable , errtablecol , errtableconstraint , errdatatype или errdomainconstraint . Данные функции существуют для того, чтобы приложения могли извлечь имя объекта базы данных, связанного с условием ошибки, так, чтобы для этого им не требовалось разбирать текст ошибки, возможно локализованный. Эти функции должны использоваться в случае ошибок, для которых может быть желательной автоматическая обработка. Для версии PostgreSQL 9.3 этот подход распространяется полностью только на ошибки класса SQLSTATE 23 (нарушение целостности ограничения), но в будущем область его применения может быть расширена.
Существует также более старая, но тем не менее активно используемая функция elog . Вызов elog :
полностью равнозначен вызову:
Заметьте, что код ошибки SQLSTATE всегда определяется неявно, а строка сообщения не подлежит переводу. Таким образом, elog следует использовать только для внутренних ошибок и отладки на низком уровне. Любое сообщение, которое может представлять интерес для обычных пользователей, должно проходить через ereport . Тем не менее, в системе есть достаточно много внутренних проверок для случаев, « которые не должны происходить » , и в них по-прежнему широко используется elog ; для таких сообщений эта функция предпочитается из-за простоты записи.
Советы по написанию хороших сообщений об ошибках можно найти в Разделе 51.3.
[13] То есть значение, которое было текущим, когда была вызвана ereport ; изменения errno во вспомогательных функциях выдачи сообщений на него не повлияют. Это будет не так, если вы запишете strerror(errno) явно в списке параметров errmsg ; поэтому делать так не нужно.