他のバージョンの文書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 | 7.3 | 7.2

9.8. 手続き言語ハンドラ

コンパイル言語 "version 1" インタフェース以外の言語で作成された関数の呼び出しは、その言語用の 呼び出しハンドラ を経由します。 (これらには、ユーザ定義の手続き言語による関数、SQL で作成された関数、version 0 コンパイル言語インタフェースを使用した関数が含まれます。)提供されたソーステキストを逐次実行するなど、その関数をきちんと実行することは、この呼び出しハンドラの責任です。この節では、言語呼び出しハンドラをどのように作成するのかについてを説明します。これは一般的な作業ではありません。 実際、古めの PostgreSQL でのみこれは有用なものでした。 しかし、この節全体の本質的な話題やその資料は PostgreSQL システムの持つ拡張性への見解を深めます。

手続き言語の呼び出しハンドラは、"普通の"関数です。 これは C のようなコンパイル言語で作成され、また、引数をとらない language_handler 型を返す関数として PostgreSQL に登録される必要があります。 この特殊な疑似型によって、このハンドラは呼び出しハンドラであることが認識され、問い合わせで直接に呼び出されることがなくなります。

Note: PostgreSQL 7.1 以降では、呼び出しハンドラは古い形式のインタフェースではなく、"version 1" 関数管理インタフェースと結び付いていなければなりません。

呼び出しハンドラは他の関数と同じ方法で呼び出されます。 引数の値と呼び出される関数の情報を持つ FunctionCallInfoData 構造体のポインタを受けとり、Datum 型の結果を返すものと想定されています。 (また、SQL NULL の結果を返すことを考慮する場合、FunctionCallInfoData 構造体の isnull フィールドを設定することもできます。) 呼び出しハンドラと呼び出される通常の関数の違いは、FunctionCallInfoData 構造体の flinfo->fn_oid フィールドが、呼び出しハンドラ自身ではなく、呼び出される実際の関数の OID を持つことです。呼び出しハンドラはこのフィールドを使用して、実行する関数を決定しなければなりません。また、渡された引数のリストは、呼び出しハンドラの宣言ではなく、対象とする関数の宣言に従って設定されます。

pg_proc エントリを取り出し、呼び出されるプロシージャの引数型と戻り値の型を解析することも呼び出しハンドラの役割です。そのプロシージャの CREATE FUNCTION で指定した AS 句は pg_proc テーブルエントリの prosrc 列にあります。これは、(PL/Tclのような)その手続き言語で記述されたソーステキスト、ファイルのパス名など呼び出しハンドラに具体的に何を実行するのかを通知するものになります。

1つのSQL 文で同じ関数が数多く呼び出されることはしばしばあります。呼び出しハンドラは、flinfo->fn_extra フィールドを使用して、呼び出される関数についての情報の検索が繰返されることを防止します。これは NULL で初期化されますが、呼び出しハンドラによって、PL 関数の情報のポインタに設定されることができます。連続した呼び出しでは、flinfo->fn_extra がすでにNULLでなければ、その内容が使用され、情報の検索段階は省略されます。呼び出しハンドラはflinfo->fn_extra が示すポインタが、少なくとも、FmgrInfo データ構造体が保持される期間である、現在の問い合わせの終りまで有効なメモリを示していることに注意しなければなりません。 この方法の 1 つは、flinfo->fn_mcxt で指定されるメモリコンテキストに余分なデータを割り当てることです。 このようなデータは通常 FmgrInfo 自身と同じ有効期間となります。しかし、ハンドラは問い合わせを跨って関数定義情報をキャッシュできるように、より長い有効期間のコンテキストを使用することを選択することもできます。

PL 関数がトリガとして呼び出された時、明示的な引数は渡されません。 しかし、FunctionCallInfoDatacontext フィールドは通常の関数呼び出しの時の NULL ではなく、TriggerData ノードを示します。言語ハンドラは PL 関数に対し、トリガ情報を入手するための機構を提供しなければなりません。

以下に、C で作成された PL ハンドラのテンプレートを示します。

#include "postgres.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "utils/elog.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 9.5 を参照して下さい。

そして、以下のようなコマンドで、サンプルの手続き言語を登録します。

CREATE FUNCTION plsample_call_handler () RETURNS language_handler
    AS '/usr/local/pgsql/lib/plsample'
    LANGUAGE C;
CREATE LANGUAGE plsample
    HANDLER plsample_call_handler;