無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

第 51章手続き言語ハンドラの作成

現在のコンパイル言語用 "Version-1" インタフェース以外のある言語で作成された関数の呼び出しはすべて、特定の言語用の 呼び出しハンドラ を経由します (これには、ユーザ定義手続き言語で作成された関数、SQLで作成された関数、コンパイル言語用Version-0インタフェースを使用した関数が含まれます)。 提供されたソーステキストを解釈するなどによって、関数の実行を意味のある方法で行うことは、呼び出しハンドラの責任です。 本章では、どのように新しい手続き言語の呼び出しハンドラを作成できるかについて概要を示します。

手続き言語用の呼び出しハンドラは "通常" の関数で、Cなどのコンパイル言語で作成し、Version-1インタフェースを使用し、引数を取らずに language_handler を返すものとして PostgreSQL に登録しなければなりません。 この特殊な仮想型は、その関数を呼び出しハンドラとして識別し、SQLコマンド内で直接その関数が呼び出されることを防止します。 C言語の呼び出し規約と動的ロードについては 項35.9 を参照してください。

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

pg_proc システムカタログから関数のエントリを取り出し、呼び出される関数の引数と戻り値の型を解析するまでを呼び出しハンドラが行います。 関数の CREATE FUNCTION コマンドの AS 句は、 pg_proc の行の prosrc 列にあります。 これは通常、手続き言語自体で作成されたソーステキストですが、理論上はファイルへのパス名や、何らかの呼び出しハンドラに詳細に何をすべきかを通知するものとすることもできます。

1つのSQL文で同じ関数が何回も呼び出されることがよくあります。 呼び出しハンドラは、 flinfo->fn_extra フィールドを使用して、呼び出す関数に関する情報を繰り返し検索することを防ぐことができます。 これは初期状態では NULL ですが、呼び出しハンドラによって呼び出す関数の情報を指すように設定することもできます。 その後の呼び出しでは、 flinfo->fn_extra が非 NULL であれば、それを使用して、情報検索の段階を省略することができます。 呼び出しハンドラは flinfo->fn_extra が少なくとも現在の問い合わせの終了まで有効なメモリを指しているかどうかを確認しなければなりません。 FmgrInfo データ構造体は長く保持される可能性があるからです。 この方法の1つとして、 flinfo->fn_mcxt で指定されたメモリコンテキスト内に余分なデータを割り当てることです。 このデータは通常 FmgrInfo 自身と同期間有効です。 しかし、ハンドラはまた、長時間メモリコンテキストにあるものを使用するかどうかを選ぶこともできます。 これにより関数定義情報を、問い合わせをまたいでキャッシュすることができます。

手続き言語関数がトリガとして呼び出された場合、引数は通常の方法では渡されず、 FunctionCallInfoData context フィールドが、普通の関数呼び出しのように NULL にはならずに、 TriggerData 構造体を指しています。 呼び出しハンドラは、手続き言語に対しトリガ情報を取り出す機構を提供しなければなりません。

以下は、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"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

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;
}

数千行のコードを上のドットの代わりに追加するだけで、呼び出しハンドラを完成することができます。

ハンドラ関数を動的ロード可能なモジュールにコンパイル( 項35.9.6 を参照してください)した後、以下のコマンドでサンプルの手続き言語を登録することができます。

CREATE FUNCTION plsample_call_handler() RETURNS language_handler
    AS '

filename

'
    LANGUAGE C;
CREATE LANGUAGE plsample
    HANDLER plsample_call_handler;

最低限の手続き言語を作成する場合には呼び出しハンドラを提供するだけで十分ですが、他にも省略可能ですが、その言語の利用をより簡便にするために提供できる2つの関数があります。 これらは 有効性検証関数 インラインハンドラ です。 有効性検証関数を提供して、 CREATE FUNCTION 時に言語固有の検査を行うことができます。 インラインハンドラを提供して、言語に DO コマンド経由の匿名コードブロック実行をサポートさせることができます。

有効性検証関数が手続き言語により提供される場合、 oid 型の単一パラメータを取る関数として宣言しなければなりません。 有効性検証関数の結果は無視されます。 そのためよく void を返すものと宣言されます。 有効性検証関数はその手続き言語で関数を作成または置換する CREATE FUNCTION の最後に呼び出されます。 渡されるOIDは関数の pg_proc 行のOIDです。 有効性検証関数は通常の方法でこの行を取り出さなければならず、そして適切な検査を実行します。 典型的な検査として、関数引数および結果の型がその言語でサポートされているかや関数本体がその言語において文法的に正しいかどうかを検証することが挙げられます。 有効性検証関数がその関数に問題がないことを判定したら、単に戻ります。 エラーがあることを判定したら、通常の ereport() エラー報告機構を使用して報告しなければなりません。 エラーを返すことで、強制的にトランザクションはロールバックされ、不正な関数定義がコミットされることを防ぎます。

有効性検証関数は通常 check_function_bodies パラメータを遵守しなければなりません。 これが無効な場合、高価または文脈次第の検査を飛ばさなければなりません。 具体的にはこのパラメータは、関数本体が他のデータベースオブジェクトに依存している可能性を考慮することなく手続き言語関数をロードできるように、 pg_dump により無効にされます。 (この仕様のため呼び出しハンドラは有効性検証関数が完全にその関数を検査したことを前提としてはいけません。 有効性検証関数を持つ目的は、呼び出しハンドラが検査を省略できることではなく、明確なエラーが CREATE FUNCTION コマンド内に存在する場合、それを即座にユーザに通知することです。) 厳密に何を検査すべきかの選択は主として有効性検査関数の裁量に委ねられていますが、 check_function_bodies が有効な場合には CREATE FUNCTION の中心となるコードは関数に関連づけられた SET 句を実行するだけですので注意して下さい。 そのため、その結果がGUCパラメータの影響を受ける検査は、ダンプをリロードする時の偽の失敗を避けるために、 check_function_bodies が無効な場合には確実に飛ばさなければなりません。

インラインハンドラが手続き言語により提供される場合、その関数は internal 型の単一パラメータを取るものとして宣言されなければなりません。 インラインハンドラの結果は無視されます。 そのためよく void を返すものと宣言されます。 インラインハンドラは特定の手続き言語で DO 文が実行された時に呼び出されます。 実際に渡されるパラメータは InlineCodeBlock 構造体のポインタです。 ここには DO 文のパラメータ、具体的には実行される匿名コードブロックのテキスト、に関する情報が含まれています。 インラインハンドラはこのコードを実行し、戻らなければなりません。

簡単な CREATE EXTENSION コマンドで言語をインストールすることが十分にできるように、これらの関数宣言と CREATE LANGUAGE コマンド自身を 拡張 としてまとめることを勧めます。 拡張の作成方法については 項35.15 を参照してください。

独自の言語ハンドラを作成する際、標準配布物に含まれる手続き言語は優れたリファレンスです。 ソースツリーの src/pl サブディレクトリを調べてください。 CREATE LANGUAGE マニュアルページもまた有用な情報を含みます。


powered by SEO.CUG.NET