支援的版本:目前 (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

54.2. 在伺服器內部報告錯誤 #

在伺服器程式碼中產生的錯誤、警告和日誌訊息應該使用 ereport,或其較舊的版本 elog 建立。這個函數的使用相當複雜,需要一些說明。

每個訊息都有兩個必需元素:一個嚴重性級別(範圍從 DEBUGPANIC,定義在 src/include/utils/elog.h 中)和一個主要訊息文字。此外,還有可選元素,最常見的是遵循 SQL 規格 SQLSTATE 慣例的錯誤識別碼。ereport 本身只是一個 shell 巨集,主要存在的原因是為了語法上的方便,使訊息產生看起來像是 C 原始碼中的單一函數呼叫。ereport 直接接受的唯一參數是嚴重性級別。主要訊息文字和任何可選訊息元素都是透過呼叫輔助函數(例如 errmsg)在 ereport 呼叫中產生。

一個典型的 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 的目前值傳回的錯誤訊息。[16] %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 是決定所需複數形式的整數值,其餘參數根據選定的格式字串進行格式化。更多資訊請參閱第 55.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,但支援訊息的各種複數形式。更多資訊請參閱第 55.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,但支援訊息的各種複數形式。更多資訊請參閱第 55.2.2 節

  • errhint(const char *msg, ...) 提供了一個可選的「提示」訊息;當提供關於如何修復問題的建議時,應該使用它,而不是關於發生了什麼錯誤的事實細節。訊息字串的處理方式與 errmsg 完全相同。

  • errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...) 類似於 errhint,但支援訊息的各種複數形式。更多資訊請參閱第 55.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() 是一個方便的函數,它為與 socket 相關的系統呼叫中的失敗選擇一個適當的 SQLSTATE 錯誤識別碼。

  • errhidestmt(bool hide_stmt) 可以呼叫它來指定抑制 postmaster 日誌中訊息的 STATEMENT: 部分。通常,如果訊息文字已經包含目前的陳述式,則這是適當的。

  • errhidecontext(bool hide_ctx) 可以呼叫它來指定抑制 postmaster 日誌中訊息的 CONTEXT: 部分。這應該僅用於詳細的偵錯訊息,其中重複包含上下文會使日誌過於膨脹。

注意

最多只能在一個 ereport 呼叫中使用函數 errtableerrtablecolerrtableconstrainterrdatatypeerrdomainconstraint。這些函數的存在是為了允許應用程式提取與錯誤條件相關聯的資料庫物件的名稱,而無需檢查可能已本地化的錯誤訊息文字。這些函數應該用於錯誤報告,應用程式可能希望對其進行自動錯誤處理。PostgreSQL 9.3 開始,僅存在 SQLSTATE 類別 23(完整性約束違規)的完整涵蓋範圍,但未來可能會擴展。

有一個較舊的函數 elog 仍被大量使用。elog 呼叫

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

完全等同於

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

請注意,SQLSTATE 錯誤代碼永遠使用預設值,且訊息字串不受翻譯影響。因此,elog 應僅用於內部錯誤和底層除錯日誌記錄。任何可能引起一般使用者注意的訊息都應該透過 ereport。儘管如此,系統中仍然有足夠多的內部 不可能發生 錯誤檢查,因此 elog 仍被廣泛使用;由於其標記簡潔性,因此對於這些訊息而言,它是首選。

關於撰寫良好錯誤訊息的建議,請參閱第 54.3 節



[16] 也就是說,當呼叫 ereport 時的當前值;輔助報告常式中對 errno 的變更不會影響它。如果您在 errmsg 的參數列表中明確地撰寫 strerror(errno),情況就不是如此了;因此,不要這樣做。

提交更正

如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的地方,請使用此表單來報告文件問題。