支援的版本:目前 (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),那將不是真的; 因此,不要這樣做。

提交更正

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