| PostgreSQL 7.4 文檔 | ||||
|---|---|---|---|---|
| Prev | Fast Backward | Fast Forward | Next | |
調用函數的時候,如果函數的書寫語言不是目前的"版本 1"的編譯語言接口(這包括用戶定義的過程語言寫的函數, 用 SQL 寫的函數,以及用版本 0 的編譯語言接口寫的函數),都會通過一個 調用句柄處理具體的語言。 調用句柄有責任用一種有意義的方法執行這個函數,比如說解析所提供的文本等等。本章簡介如何書寫一個新的過程語言調用句柄。
過程語言的調用句柄是一個"普通"的函數, 必須使用一種編譯語言來寫,比如 C,使用版本-1的接口,並且在 PostgreSQL 裡注冊成接受零個參數並且返回類型 language_handler。 這個特殊的偽類型標識該函數為一個調用句柄並且避免它直接在 SQL 命令中被調用。
調用句柄的調用方式和其它函數一樣:它接受一個指向一個 FunctionCallInfoData struct 的指針,這個指針包含參數值和有關被調用的函數的信息, 並且預期它返回一個 Datum 結果(如果它希望返回一個 SQL 的空結果, 那麼可能設置 isnull 字段)。 調用句柄和普通的被調函數的區別是 FunctionCallInfoData 結構的 flinfo->fn_oid 字段強包含實際要調用的函數的 OID, 而不是調用句柄自身。調用句柄必須使用這個字段判斷要執行哪個函數。 通常,傳遞進來的參數列表也是按照目標函數的聲明設置的,而不是給調用句柄設置的。
從系統表 pg_proc 裡抓取函數入口以及分析被調函數的參數和返回類型就是調用句柄的事了。 來自 CREATE FUNCTION 中的 AS 子句將會在 pg_proc 行的 prosrc 字段中找到。這個可能是過程語言本身的源文本(比如 PL/Tcl),一個指向某個文件的路徑名, 或者任何告訴調用句柄如何詳細處理的東西。
通常,每個 SQL 語句裡面可能要調用同一個函數多次。 調用句柄可以利用 flinfo->fn_extra 字段避免重復地查找有關被調函數地信息。 這個字段初始為 NULL,但是可以被調用句柄設置為指向有關被調函數的信息。 在隨後的調用中,如果 flinfo->fn_extra 已經為非NULL,那麼就可以直接使用它而免于重新查找信息。 調用句柄必須確保 flinfo->fn_extra 是用于指向一塊至少會生存到當前查詢結束的內存區裡, 因為一個 FmgrInfo 數據結構將會保存那麼長的時間。 一個實現這個要求的方法是在 flinfo->fn_mcxt 聲明的內存環境裡分配一塊額外的數據; 這樣的數據通常和 FmgrInfo 自己有一樣的生命期。 但是句柄也可以同樣選擇使用一個更長生存期的環境,這樣它就可以跨查詢緩存函數定義。
在過程語言函數以觸發器的形式調用的時候,就沒有什麼參數以通常的方式傳遞進來, 而是 FunctionCallInfoData 的 context 字段指向一個 TriggerData 結構, 而不是像普通函數調用裡面的 NULL 那樣。一個語言句柄應該為過程語言函數提供獲取觸發器信息的機制。
下面是一個用 C 寫的永遠過程語言句柄的模版:
#include "postgres.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "utils/syscache.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
PG_FUNCTION_INFO_V1(plsample_call_handler);
Datum
plsample_call_handler(PG_FUNCTION_ARGS)
{
Datum retval;
if (CALLED_AS_TRIGGER(fcinfo))
{
/*
* 以觸發器過程調用
*/
TriggerData *trigdata = (TriggerData *) fcinfo->context;
retval = ...
}
else
{
/*
* 以函數調用
*/
retval = ...
}
return retval;
}在打點的地方放上幾千行代碼就可以完成調用句柄。
在把句柄函數編譯成一個可裝載的模塊(參閱 Section 33.7.6)之後, 下面的命令就可以注冊這個例子過程語言:
CREATE FUNCTION plsample_call_handler() RETURNS language_handler
AS 'filename'
LANGUAGE C;
CREATE LANGUAGE plsample
HANDLER plsample_call_handler;