2025年9月25日: PostgreSQL 18 釋出!
支援的版本:當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

55.2. 伺服器內部報告錯誤 #

伺服器程式碼內部生成的錯誤、警告和日誌訊息應使用 ereport 或其舊版本 elog 來建立。該函式的使用足夠複雜,需要一些解釋。

每條訊息都有兩個必需的元素:嚴重性級別(從 DEBUGPANIC,在 src/include/utils/elog.h 中定義)和主要訊息文字。此外,還有可選的元素,其中最常見的是一個錯誤識別符號程式碼,它遵循 SQL 規範的 SQLSTATE 約定。 ereport 本身只是一個 shell 宏,主要用於語法便利性,使訊息生成在 C 原始碼中看起來像一個單一的函式呼叫。 ereport 直接接受的唯一引數是嚴重性級別。主要訊息文字和任何可選的訊息元素是透過在 ereport 呼叫中呼叫輔助函式(如 errmsg)來生成的。

典型的 ereport 呼叫可能如下所示:

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

這指定了錯誤嚴重性級別 ERROR(一種普通的錯誤)。 errcode 呼叫使用在 src/include/utils/errcodes.h 中定義的宏來指定 SQLSTATE 錯誤程式碼。 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."));

這說明了如何使用格式程式碼將執行時值嵌入到訊息文字中。此外,還提供了一個可選的“提示”訊息。輔助函式呼叫可以按任何順序編寫,但按照慣例,errcodeerrmsg 會先出現。

如果嚴重性級別為 ERROR 或更高,ereport 會中止當前查詢的執行,並且不會返回到呼叫者。如果嚴重性級別低於 ERRORereport 會正常返回。

可用的 ereport 輔助例程是:

  • errcode(sqlerrcode) 指定條件的 SQLSTATE 錯誤識別符號程式碼。如果未呼叫此例程,則當錯誤嚴重性級別為 ERROR 或更高時,錯誤識別符號預設為 ERRCODE_INTERNAL_ERROR;當錯誤級別為 WARNING 時,預設為 ERRCODE_WARNING;否則(對於 NOTICE 及以下),預設為 ERRCODE_SUCCESSFUL_COMPLETION。雖然這些預設值通常很方便,但在省略 errcode() 呼叫之前,請務必考慮它們是否合適。

  • errmsg(const char *msg, ...) 指定主要錯誤訊息文字,以及可能要插入其中的執行時值。插入項由 sprintf 風格的格式程式碼指定。除了 sprintf 接受的標準格式程式碼外,還可以使用格式程式碼 %m 來插入 strerror 為當前 errno 值返回的錯誤訊息。[18] %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 是決定需要哪種複數形式的整數值,其餘引數根據所選格式字串進行格式化。有關更多資訊,請參閱 第 56.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,但支援訊息的各種複數形式。有關更多資訊,請參閱 第 56.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,但支援訊息的各種複數形式。有關更多資訊,請參閱 第 56.2.2 節

  • errhint(const char *msg, ...) 提供一個可選的“提示”訊息;當提供解決問題的建議時使用,而不是關於錯誤發生的事實細節。訊息字串的處理方式與 errmsg 相同。

  • errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...) 類似於 errhint,但支援訊息的各種複數形式。有關更多資訊,請參閱 第 56.2.2 節

  • 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 錯誤識別符號。

  • errhidestmt(bool hide_stmt) 可用於指定在主程序日誌中抑制訊息的 STATEMENT: 部分。通常,如果訊息文字已包含當前語句,則此操作是合適的。

  • errhidecontext(bool hide_ctx) 可用於指定在主程序日誌中抑制訊息的 CONTEXT: 部分。這僅應用於冗長的除錯訊息,其中重複包含上下文會使日誌膨脹過多。

注意

ereport 呼叫中最多應使用 errtableerrtablecolerrtableconstrainterrdatatypeerrdomainconstraint 中的一個。這些函式的存在是為了讓應用程式能夠提取與錯誤條件相關的資料庫物件的名稱,而無需檢查可能已本地化的錯誤訊息文字。這些函式應在可能需要應用程式進行自動錯誤處理的錯誤報告中使用。截至 PostgreSQL 9.3,完整的覆蓋僅限於 SQLSTATE 類 23(完整性約束衝突)中的錯誤,但這可能會在將來擴充套件。

還有一個較舊的函式 elog,它仍然被大量使用。一個 elog 呼叫

elog(level, "format string", ...);

等同於:

ereport(level, errmsg_internal("format string", ...));

請注意,SQLSTATE 錯誤程式碼始終是預設值,訊息字串不會被翻譯。因此,elog 應僅用於內部錯誤和低階除錯日誌記錄。任何可能引起普通使用者關注的訊息都應透過 ereport 處理。儘管如此,系統中仍有大量的內部“不可能發生”錯誤檢查,因此 elog 仍然被廣泛使用;由於其記法簡單,它更適合用於這些訊息。

有關編寫良好錯誤訊息的建議,請參閱 第 55.3 節



[18] 也就是說,到達 ereport 呼叫時 errno 的值;在輔助報告例程中 errno 的更改不會影響它。如果您在 errmsg 的引數列表中顯式寫入 strerror(errno),則情況並非如此;因此,請勿這樣做。

提交更正

如果您在文件中發現任何不正確、與您對特定功能的實際體驗不符或需要進一步闡明的內容,請使用 此表單 報告文件問題。