PostgreSQL 在服務器中報告錯誤

2021-09-15 09:38 更新

服務器代碼內(nèi)產(chǎn)生的錯誤、警告和日志消息應該使用ereport或者更老的elog生成。這個函數(shù)的使用有些復雜,因此有必要做一些解釋。

對于每一個消息都有兩個必要的元素:一個嚴重性級別(從DEBUGPANIC)和一個主消息文本。此外還有一些可選元素,其中最常見的是一個遵守 SQL 規(guī)范中 SQLSTATE 習慣的錯誤標識符代碼。ereport本身只是一個 shell 宏,它的存在主要是為了在語法習慣上讓消息的產(chǎn)生更像 C 源代碼中的單個函數(shù)調用而已。 ereport直接接受的唯一參數(shù)是嚴重性級別。主消息文本和任何其他可選消息元素通過在ereport調用中使用輔助函數(shù)產(chǎn)生,例如errmsg。

對于ereport的一次典型調用可能看起來像:

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

這會指定錯誤嚴重性級別為ERROR(一個普通錯誤)。errcode調用使用src/include/utils/errcodes.h中定義的一個宏指定 SQLSTATE 錯誤代碼。errmsg調用提供主消息文本。

您還會經(jīng)??吹竭@種較舊的樣式,在輔助函數(shù)調用周圍有一組額外的圓括號:

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

PostgreSQL 版本 12 之前需要額外的括號,但現(xiàn)在是可選的。

這里有一個更復雜的例子:

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."));

這展示了使用格式代碼把運行時值嵌入到一個消息文本中的方法,其中還提供了一個可選的hint消息。 輔助函數(shù)調用可以按任何順序寫入,但通常先出現(xiàn)errcodeerrmsg。

如果嚴重級別是ERROR或更高,ereport 會中止當前查詢的執(zhí)行并且不會返回到調用者。如果嚴重級別低于 ERROR,ereport會正常返回。

ereport可用的輔助例程是:

  • errcode(sqlerrcode)指定對于該情況的 SQLSTATE 錯誤標識符代碼。如果沒有調用這個例程,錯誤嚴重性級別是ERROR或更高時錯誤標識符會默認成ERRCODE_INTERNAL_ERROR,錯誤級別是WARNING時標識符為ERRCODE_WARNING,否則(對于 NOTICE及以下的級別)標識符會被設置為ERRCODE_SUCCESSFUL_COMPLETION。雖然這些默認值常常很方便,在忽略errcode()調用之前請總是思考一下它們是否合適。

  • errmsg(const char *msg, ...)指定主錯誤消息文本,以及需要插入其中的運行時值。這種插入以sprintf-風格的格式代碼指定。除了sprintf接受的標準格式代碼,格式代碼%m可以用來插入由strerrorerrno的當前值返回的錯誤消息。 [14] %m不要求errmsg參數(shù)列表中的任何對應項。注意在格式代碼被處理之前,消息字符串將通過 gettext來進行可能的本地化。

  • errmsg_internal(const char *msg, ...)errmsg相同,不過消息串將不會被翻譯,也不會被包括在國際化的消息字典中。這不應該被用于不能發(fā)生的情況中,因為那些情況下不值得花費精力去做翻譯。

  • errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)很像errmsg,但是支持消息的多種復數(shù)形式。fmt_singular是英語單數(shù)格式,fmt_plural是英語復數(shù)格式,n是決定需要何種復數(shù)形式的整數(shù)值,剩下的參數(shù)會被根據(jù)選中的格式字符串進行格式化。詳見 第 54.2.2 節(jié)

  • 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相似,但是支持消息的多種復數(shù)形式。詳見第 54.2.2 節(jié)。

  • errdetail_log(const char *msg, ...)errdetail相同,除了這個字符串只會進入服務器的日志而不會發(fā)往客戶端。如果同時使用了errdetail(或者上述的一種等效函數(shù))以及errdetail_log,那么一個字符串會被發(fā)往客戶端而另一個會被發(fā)往日志。如果錯誤細節(jié)的安全性過于敏感或者體積過于龐大而不適合于發(fā)往客戶端,這個函數(shù)就非常有用。

  • errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)errdetail_log 相似,但是支持多種復數(shù)形式的消息。詳見第 54.2.2 節(jié)。

  • errhint(const char *msg, ...)提供一個可選的hint消息,它被用來提供關于如何修復該問題的建議。該消息字符串以和errmsg相同的方式處理。

  • errcontext(const char *msg, ...)通常不會被直接從一個ereport消息站點調用,它被用在error_context_stack回調函數(shù)中來提供錯誤發(fā)生的上下文,例如一個 PL 函數(shù)中的當前位置。該消息字符串以和errmsg相同的方式處理。不同于其他輔助函數(shù),在每次 ereport調用中可以多次調用這個函數(shù),這樣提供的連續(xù)的字符串將被用單獨的新行串接在一起。

  • errposition(int cursorpos)指定一個查詢字符串中錯誤的文本位置。當前,它只對查詢處理的詞法和語法分析階段中檢測到的錯誤有用。

  • errtable(Relation rel)指定一個關系,它的名稱和模式名稱應該被包括在錯誤報告中作為輔助域。

  • errtablecol(Relation rel, int attnum)指定一個列,它的名稱、表名和模式名稱應該被包括在錯誤報告中作為輔助域。

  • errtableconstraint(Relation rel, const char *conname)指定一個約束,它的名稱、表名和模式名稱應該被包括在錯誤報告中作為輔助域。索引應當為考慮成用于這種目的的約束,不管它們有沒有一個相關聯(lián)的pg_constraint項。要小心地以rel傳遞底層堆關系而不是索引本身。

  • errdatatype(Oid datatypeOid)指定一個數(shù)據(jù)類型,它的名稱和模式名稱應該被包括在錯誤報告中作為輔助域。

  • errdomainconstraint(Oid datatypeOid, const char *conname)指定一個域約束,它的名稱、域名和模式名稱應該被包括在錯誤報告中作為輔助域。

  • errcode_for_file_access()是一個便捷函數(shù),它可以在一個文件訪問相關的系統(tǒng)調用中為一個失敗選擇一個合適的 SQLSTATE 錯誤標識符。它使用保存下來的errno來決定要差生哪種錯誤代碼。通常,應該把它和主錯誤消息文本中的%m聯(lián)合使用。

  • errcode_for_socket_access()是一個便捷函數(shù),它可以在一個套接字相關的系統(tǒng)調用中為一個失敗選擇一個合適的 SQLSTATE 錯誤標識符。

  • errhidestmt(bool hide_stmt)可以被調用來指定 postmaster 日志中一個消息的STATEMENT:部分的禁止。通常如果該消息文本已經(jīng)包括當前語句這就是合適的。

  • 可以調用errhidecontext(bool hide_ctx)來指示抑制 postmaster 日志中消息里的CONTEXT:部分。這只應該被用于 verbose 模式的調試消息,這類消息中被重復包含的上下文信息會讓日志膨脹得非常厲害。

注意

在一個ereport調用中,最多可以使用一個errtableerrtablecol、errtableconstraint、errdatatype或者errdomainconstraint函數(shù)。這些函數(shù)存在是為了允許應用抽取與錯誤情況相關的數(shù)據(jù)庫對象名,而不需要檢查可能已被本地化的錯誤消息文本。這些函數(shù)應該被用在應用需要對其進行自動錯誤處理的錯誤報告中。從 PostgreSQL9.3 開始,完整的覆蓋只為 SQLSTATE 類別 23 中的錯誤存在(完整性約束違背),但是在未來這些很可能會被擴展。

有一個還在大量使用的舊的函數(shù)elog。一個elog調用:

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

完全等效于:

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

注意 SQLSTATE 錯誤代碼總是被給予默認值,并且消息字符串不受翻譯限制。因此,elog應該只被用于內(nèi)部錯誤和低層次的調試日志。任何普通用戶感興趣的消息應該通過ereport。不管怎樣,在仍廣泛使用elog的系統(tǒng)中,有足夠多的內(nèi)部不可能發(fā)生的錯誤檢查,出于記號簡潔的目的這更適合于那些消息。

有關編寫好的錯誤消息的建議可見第 53.3 節(jié)。



[14] 也就是說,該值時到達ereport調用時的當前值,在輔助報告例程內(nèi)errno的改變不會影響它。但如果你在errmsg的參數(shù)列表中顯式地寫了strerror(errno)則不是這樣,因此不要那樣做。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號