呼叫以非目前編譯語言的「版本 1」介面撰寫的函式(包括使用者定義的程序語言中的函式以及以 SQL 撰寫的函式)的所有呼叫,都必須通過特定語言的呼叫處理器函式。呼叫處理器的責任是以有意義的方式執行函式,例如解釋提供的原始碼文字。本章概述如何撰寫新的程序語言的呼叫處理器。
程序語言的呼叫處理器是一個「正常」函式,必須使用版本 1 介面以 C 等編譯語言撰寫,並以不帶引數且傳回 language_handler
型別的方式向 PostgreSQL 註冊。此特殊的虛擬型別將函式識別為呼叫處理器,並防止其直接在 SQL 命令中呼叫。有關 C 語言呼叫慣例和動態載入的更多詳細資訊,請參閱第 36.10 節。
呼叫處理器的呼叫方式與任何其他函式相同:它接收指向包含引數值和有關被呼叫函式資訊的 FunctionCallInfoBaseData
struct
的指標,並且預期傳回 Datum
結果(並且如果希望傳回 SQL 空值結果,則可能會設定 FunctionCallInfoBaseData
結構的 isnull
欄位)。呼叫處理器和普通被呼叫函式之間的差異在於 FunctionCallInfoBaseData
結構的 flinfo->fn_oid
欄位將包含要呼叫的實際函式的 OID,而不是呼叫處理器本身的 OID。呼叫處理器必須使用此欄位來確定要執行的函式。此外,傳遞的引數清單已根據目標函式的宣告(而不是呼叫處理器的宣告)進行設定。
由呼叫處理器從 pg_proc
系統目錄中獲取函式的條目,並分析被呼叫函式的引數和傳回型別。函式的 CREATE FUNCTION
命令中的 AS
子句將在 pg_proc
列的 prosrc
欄位中找到。這通常是程序語言中的原始碼文字,但理論上它可以是其他內容,例如檔案的路徑名稱,或以詳細方式告訴呼叫處理器該做什麼的任何其他內容。
通常,每個 SQL 陳述式都會多次呼叫同一個函式。呼叫處理器可以透過使用 flinfo->fn_extra
欄位來避免重複查閱有關被呼叫函式的資訊。這最初將是 NULL
,但可以由呼叫處理器設定為指向有關被呼叫函式的資訊。在後續呼叫中,如果 flinfo->fn_extra
已經是非 NULL
,則可以使用它並跳過資訊查閱步驟。呼叫處理器必須確保 flinfo->fn_extra
指向至少在目前查詢結束之前存在的記憶體,因為 FmgrInfo
資料結構可能會保留這麼長時間。一種方法是在 flinfo->fn_mcxt
指定的記憶體環境中配置額外資料;此類資料通常具有與 FmgrInfo
相同的生命週期。但是處理器也可以選擇使用更長壽命的記憶體環境,以便它可以跨查詢快取函式定義資訊。
當程序語言函式作為觸發器呼叫時,不會以通常的方式傳遞引數,但是 FunctionCallInfoBaseData
的 context
欄位指向 TriggerData
結構,而不是像普通函式呼叫中那樣為 NULL
。語言處理器應提供機制,讓程序語言函式能夠取得觸發器資訊。
以 C 擴充功能撰寫的程序語言處理器的範本在 src/test/modules/plsample
中提供。這是一個可運作的範例,示範了建立程序語言處理器、處理參數和傳回值的一種方法。
儘管提供呼叫處理器足以建立最小的程序語言,但還可以選擇提供另外兩個函式,以使該語言更易於使用。這些是驗證器和內嵌處理器。可以提供驗證器,以允許在CREATE FUNCTION期間完成特定於語言的檢查。可以提供內嵌處理器,以允許該語言支援透過DO命令執行的匿名程式碼區塊。
如果驗證器是由程序語言提供,則必須將其宣告為一個函數,該函數接受一個型別為 oid
的單一參數。 驗證器的結果會被忽略,所以通常宣告為回傳 void
。驗證器會在執行完 CREATE FUNCTION
指令時被呼叫,該指令已建立或更新一個以程序語言編寫的函數。傳入的 OID 是函數在 pg_proc
資料列中的 OID。驗證器必須以一般方式提取此列,並執行任何適當的檢查。首先,呼叫 CheckFunctionValidatorAccess()
以診斷使用者無法透過 CREATE FUNCTION
達成的驗證器的明確呼叫。典型的檢查包括驗證函數的參數和結果型別是否受語言支援,以及函數主體在語言中是否語法正確。如果驗證器發現函數沒問題,就應該直接回傳。如果發現錯誤,則應透過正常的 ereport()
錯誤報告機制來報告。擲回錯誤將強制交易回滾,從而防止不正確的函數定義被提交。
驗證器函數通常應遵守 check_function_bodies 參數:如果關閉此參數,則應略過任何昂貴或與上下文相關的檢查。如果該語言允許在編譯時執行程式碼,則驗證器必須禁止會導致此類執行的檢查。特別是,pg_dump 會關閉此參數,以便它可以載入程序語言函數,而無需擔心函數主體的副作用或對其他資料庫物件的相依性。(由於此要求,呼叫處理常式應避免假設驗證器已完全檢查過函數。擁有驗證器的目的不是讓呼叫處理常式省略檢查,而是立即通知使用者 CREATE FUNCTION
指令中是否存在明顯的錯誤。)雖然確切檢查哪些內容主要由驗證器函數自行決定,但請注意,核心 CREATE FUNCTION
程式碼僅在 check_function_bodies
為開啟時,才會執行附加到函數的 SET
子句。因此,當 check_function_bodies
為關閉時,應絕對略過其結果可能受 GUC 參數影響的檢查,以避免在還原傾印時發生錯誤。
如果程序語言提供內聯處理常式,則必須將其宣告為一個函數,該函數接受一個型別為 internal
的單一參數。內聯處理常式的結果會被忽略,所以通常宣告為回傳 void
。當執行指定程序語言的 DO
陳述式時,將會呼叫內聯處理常式。實際傳遞的參數是指向 InlineCodeBlock
結構的指標,該結構包含有關 DO
陳述式的參數的資訊,特別是要執行的匿名程式碼區塊的文字。內聯處理常式應執行此程式碼並回傳。
建議您將所有這些函數宣告,以及 CREATE LANGUAGE
指令本身,包裝到一個 擴充套件中,以便簡單的 CREATE EXTENSION
指令就足以安裝該語言。 有關編寫擴充套件的資訊,請參閱第 36.17 節。
當嘗試編寫自己的語言處理常式時,標準發行版中包含的程序語言是很好的參考。請查看原始碼樹的 src/pl
子目錄。CREATE LANGUAGE 參考頁面也包含一些有用的詳細資訊。
如果您在文件中發現任何不正確,與您使用特定功能的經驗不符或需要進一步澄清的內容,請使用此表單來回報文件問題。