ブロック内で使用される、行、レコードといった全ての変数はそのブロックの宣言部で宣言されなければなりません(唯一の例外は、FOE ループである整数値の範囲に渡って繰り返されるループ変数で、これは、自動的に整数型変数として宣言されます)。
PL/pgSQL 変数は、INTEGER、VARCHAR、CHAR といった、任意のSQL データ型を持つことができます。
変数宣言の例を以下に示します。
user_id INTEGER; quantity NUMERIC(5); url VARCHAR; myrow tablename%ROWTYPE; myfield tablename.fieldname%TYPE; arow RECORD;
変数宣言の一般的な構文は以下の通りです。
name [ CONSTANT ] type [ NOT NULL ] [ { DEFAULT | := } expression ];
DEFAULT 句が指定された場合、ブロックに入った時に代入される初期値を指定します。DEFAULT 句が指定されない場合、変数は SQL の NULL 値に初期化されます。
CONSTANT オプションにより、そのブロック内でその値が不変になるように、その変数への代入は禁止されます。 NOT NULL が指定された場合、NULL 値の代入は実行時エラーになります。NOT NULL として宣言した変数はすべて、デフォルト値を指定しなければなりません。
デフォルト値はブロックに入る度に評価されます。ですから、例えば、'now' を timestamp 型の変数に代入することで、その変数には、関数のプリコンパイルした時刻ではなく、関数呼び出し時の現在時刻が格納されます。
例
quantity INTEGER DEFAULT 32; url varchar := ''http://mysite.com''; user_id CONSTANT INTEGER := 10;
name ALIAS FOR $n;
関数に渡される引数の名前には $1, $2 という識別子が付けられます。 オプションとして、$n 引数に別名を定義することができ、可読性が向上します。別名、数字による識別子の両方とも引数の値を参照する時に使用することができます。以下に例を示します。
CREATE FUNCTION sales_tax(REAL) RETURNS REAL AS ' DECLARE subtotal ALIAS FOR $1; BEGIN return subtotal * 0.06; END; ' LANGUAGE 'plpgsql'; CREATE FUNCTION instr(VARCHAR,INTEGER) RETURNS INTEGER AS ' DECLARE v_string ALIAS FOR $1; index ALIAS FOR $2; BEGIN -- ここで何らかの処理を行う END; ' LANGUAGE 'plpgsql'; CREATE FUNCTION use_many_fields(tablename) RETURNS TEXT AS ' DECLARE in_t ALIAS FOR $1; BEGIN RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7; END; ' LANGUAGE 'plpgsql';
name tablename%ROWTYPE;
複合型の変数は、行変数 (または行型変数) と呼ばれます。こういった変数には、問い合わせの列集合が変数の型宣言と一致する限り、SELECT や FOR 問い合わせの結果の行全体を保持することができます。行変数の個々のフィールド値には、例えば、rowvar.field といったドット記法を使用してアクセスすることができます。
現在、行変数は %ROWTYPE 表記を使用することでのみ宣言することができます。 テーブル名そのものを型宣言として使用できればと考えるかもしれませんが、これは PL/pgSQL 関数内では受け付けられません。
関数へのパラメータは複合型をとることができます (テーブル行全体)。その場合、対応する識別子 $n は行変数であり、そのフィールドを、例えば、$1.user_id で選択することができます。
テーブル行のユーザ定義の属性のみに行型変数でアクセスすることができます。OID やその他のシステム属性にはアクセスできません (ビューからの行があり得るためです)。 行型のフィールドは、例えば char(n) などのテーブルのフィールドの大きさやデータ型の精度を継承します。
CREATE FUNCTION use_two_tables(tablename) RETURNS TEXT AS ' DECLARE in_t ALIAS FOR $1; use_t table2name%ROWTYPE; BEGIN SELECT * INTO use_t FROM table2name WHERE ... ; RETURN in_t.f1 || use_t.f3 || in_t.f5 || use_t.f7; END; ' LANGUAGE 'plpgsql';
name RECORD;
レコード変数は行型変数と似ていますが、事前に定義された構造を持っていません。これはSELECT やFOR コマンドの間で代入された行の実際の行構造をとります。レコード変数の副構造は、代入を行う度に変更できます。 つまり、レコード変数は、最初に代入されるまで副構造を持たず、従って、フィールドへのアクセスを試みると実行時エラーが発生します。
RECORD は本当のデータ型ではなく、単なるプレースホルダであることに注意して下さい。
%TYPE および %ROWTYPE 属性を使用して、他のデータベース項目(例えばテーブルのフィールド)として同じデータ型または構造を持つ変数を宣言することができます。
%TYPE は変数やデータベースの列のデータ型を提供します。これを使用してデータベース値を保持する変数を宣言することができます。例えば、users テーブルに user_id という列があるものとします。users.user_id と同じデータ型の変数を宣言するには、以下のように記述します。
user_id users.user_id%TYPE;
%TYPE を使用することで、参照する構造のデータ型を把握する必要がなくなります。 また、これが最も重要なことですが、参照される項目のデータ型が将来変更された(例えば、user_id のテーブル定義を INTEGER から REAL に変更した)場合でも、関数定義を変更する必要がない可能性があります。
%ROWTYPE は指定されたテーブルの行全体に対応する複合データ型を提供します。 table はデータベースの既存のテーブルまたはビュー名でなければなりません。
DECLARE users_rec users%ROWTYPE; user_id users.user_id%TYPE; BEGIN user_id := users_rec.user_id; ... CREATE FUNCTION does_view_exist(INTEGER) RETURNS bool AS ' DECLARE key ALIAS FOR $1; table_data cs_materialized_views%ROWTYPE; BEGIN SELECT INTO table_data * FROM cs_materialized_views WHERE sort_key=key; IF NOT FOUND THEN RETURN false; END IF; RETURN true; END; ' LANGUAGE 'plpgsql';
RENAME oldname TO newname;
RENAME 宣言を使用して、変数、レコード、行の名前を変更することができます。これは主に、トリガプロシージャの内側で NEW や OLD を別の名前で参照しなければならない場合に有用です。 ALIAS も参照してください。
例
RENAME id TO user_id; RENAME this_var TO that_var;
Note: RENAME は、PostgreSQL 7.3 の時点では壊れているようです。この改修は優先順位は低いです。 ALIAS で RENAME の実用的な使用方法のほとんどを代用できるからです。