PL/pgSQL - SQL手続き言語

PostgreSQL 8.0.0 文書
前のページ | 巻戻し |  | 早送り | 次のページ

# 第 35章PL/pgSQL - SQL手続き言語

PL/pgSQLは、PostgreSQLデータベースシステム用の読み込み可能な手続き言語です。 PL/pgSQLの設計目的は、次のような読み込み可能な手続き言語でした。

- 関数とトリガプロシージャを作成するために使用できること

- SQL言語に制御構造を追加すること

- 複雑な演算が可能であること

- 全てのユーザ定義型、関数、演算子を継承すること

- サーバによって信頼できるものと定義できること

- 使いやすいこと

ユーザ定義型用の入出力変換と計算関数を除き、C言語関数で定義できる事は全てPL/pgSQLでも実現できます。 例えば、複雑な条件のある演算処理関数の作成が可能ですし、作成した関数を使用して演算子を定義することも、インデックス式にその関数を使用することも可能です。

# 35.1. 概要

PL/pgSQL呼び出しハンドラは関数のソーステキストを解析し、初めてその関数が(各セッションで)呼び出された時にバイナリ形式の命令ツリーを内部で作成します。 この命令ツリーは完全にPL/pgSQL文構造に変換されますが、関数内部の個々のSQL式とSQLコマンドは即座に変換されません。

各式やSQLコマンドが初めてその関数で使用される時に、PL/pgSQLインタプリタは(SPIマネージャの`SPI_prepare`、`SPI_saveplan`関数を使用して)実行計画の準備を行います。 その後にその式やコマンドが行われる時には、その準備された計画を再利用します。 こうして、実行計画が必要とされる問い合わせを多く持つ、条件付きコードを持つ関数では、そのデータベース接続が有効な間実際に使用された部分についてのみ、計画の準備と保存が行われます。 これにより、解析にかかる総時間をかなり短縮し、PL/pgSQL関数の文の問い合わせ計画を生成することができます。 欠点は特定の式や問い合わせのエラーが、関数の該当部分が実行されるまで検出されないことです。

PL/pgSQLが関数内の特定のコマンド用の問い合わせ計画を作成すると、そのデータベース接続が有効な間、その計画は再利用されます。 通常これにより性能は向上しますが、動的にデータベーススキーマを変更する場合は問題がいくつか発生します。 例えば、以下のようにします。

    CREATE FUNCTION populate() RETURNS integer AS $$
    DECLARE
        -- 宣言部
    BEGIN
        PERFORM my_function();
    END;
    $$ LANGUAGE plpgsql;

上の関数を実行すると、`PERFORM`文用に生成された問い合わせ計画では、`my_function()`のOIDを参照します。 後に、`my_function()`を削除し、再作成すると、`populate()`は`my_function()`を見つけることができなくなります。 その場合、新たにコンパイルされるように`populate()`を再作成、または、少なくともデータベースセッションを新しく起動しなければなりません。 この他に、`my_function()`の定義を更新する時に、`CREATE OR REPLACE FUNCTION`を使用することでこの問題を防ぐことができます。 (関数が"置き換えられる"時に、そのOIDが変わりません。)

このようにPL/pgSQLは実行計画を保存しますので、PL/pgSQL関数内に直接現れるSQLコマンドは実行の度に同じテーブルとフィールドを参照しなければなりません。 つまり、SQLコマンドにて、テーブルやフィールドの名前としてパラメータを使用することができません。 実行の度に新しく問い合わせ計画を作成する無駄を覚悟で、PL/pgSQLの`EXECUTE`文を使った動的問い合わせを構成することで、この制限を回避できます。

> 注意: PL/pgSQL `EXECUTE` 文は PostgreSQL サーバでサポートされているEXECUTE SQL 文とは関連がありません。 サーバの `EXECUTE` 文は PL/pgSQL 関数内で使用することはできません (使用する必要もありません)。

## 35.1.1. PL/pgSQLを使用することの利点

SQL は PostgreSQL およびその他のほとんどのリレーショナルデータベースが問い合わせ言語として使用している言語です。 移植性があり、習得が容易です。 しかし、あらゆる SQL 文はデータベースサーバによって個々に実行されなければいけません。

これはクライアントアプリケーションに対して以下のようなことを要求しています。 まず、データベースサーバに問い合わせを送信します。 次にそれが処理されるのを待ちます。 次に、結果を取得します。 次に若干の計算を行います。 そして、サーバに次の問い合わせを送信します。 クライアントがデータベースサーバマシンと異なるマシンの場合、プロセス間通信を招き、ネットワーク・オーバーへッドを起こすかもしれません。

PL/pgSQLを使うことで、計算と複数の問い合わせをデータベースサーバ内部にひとまとめに実行することができます。 このように、手続き言語の能力とSQLの使いやすさを持ち合わせているにもかかわらず、全てにおいてクライアント/サーバ通信のオーバーへッドがないのでかなりの処理時間を節約できます。 これによりかなり性能を向上させることができます。

また、PL/pgSQLではSQL全てのデータ型、演算子、関数を使用することができます。

## 35.1.2. 引数と結果データ型のサポート

PL/pgSQLで作成された関数は、サーバでサポートされる任意のスカラデータ型や配列データ型を引数として受け付けることができ、また、これらの型を結果として返すことができます。 また、任意の、名前で指定された複合型(行型)を受け付けたり、返したりすることもできます。 更に、PL/pgSQL関数を、項7.2.1.4で説明される、呼び出す問い合わせ中の仕様で決定される列を持つ行型である、`record`を返すように宣言することも可能です。

また、PL/pgSQL関数を、`anyelement`と`anyarray`多様型を受け付けたり、返したりするように宣言することもできます。 項31.2.5の説明とおり、多様関数で扱われるデータ型は呼出し毎に変動することができます。 例を項35.4.1に示します。

PL/pgSQL関数を、"集合"、テーブル、一つのインスタンスを返す任意のデータ型を返すように宣言することもできます。 こうした関数は、結果集合の必要な要素に対して`RETURN NEXT`を実行することで、その出力を生成します。

最後に、有用な戻り値を持たない場合、PL/pgSQL関数は、`void`を返すように宣言することができます。

PL/pgSQL は現在ドメイン型を完全にはサポートしていません。 ドメインは基本的なスカラ型と同様に取り扱われます。 これはドメインに関する制約が、実施されないことを意味します。 これは関数の引数に関する問題ではありませんが、ドメイン型を戻り値とする PL/pgSQL 関数を宣言する時の障害となります。

前のページ | ホーム | 次のページ
手続き言語 | 上に戻る | PL/pgSQLによる開発向けのヒント