F.39. spi

spiモジュールは、SPIおよびトリガを使用した、動作可能な例を複数提供します。 これらの関数は独自の何らかの価値を持つものですが、目的に応じて変更するための例としてより有用です。 関数は任意のテーブルと使用できるほど一般的なものですが、トリガを作成する場合は(後述のように)テーブル名とフィールド名を指定する必要があります。

以下で説明する関数グループのそれぞれは、別々にインストールすることができる拡張として提供されます。

F.39.1. refint — 参照整合性を実装する関数

check_primary_key()およびcheck_foreign_key()は、外部キー制約を検査するために使用されます。 (当然ながら、この機能はかなり前に組み込みの外部キー機能に取って代わりました。しかし例としてはまだ有用です。)

check_primary_key()は参照テーブルを検査します。 使用方法は、この関数を使用するBEFORE INSERT OR UPDATEトリガを他のテーブルを参照するテーブルに作成することです。 トリガ引数は、外部キーを形成する参照テーブルの列名、被参照テーブル名、プライマリ/一意キーを形成する被参照テーブルの列名です。 複数の外部キーを扱うためには、各参照に対してトリガを作成してください。

check_foreign_key()は被参照テーブルを検査します。 使用方法は、この関数を使用するBEFORE DELETE OR UPDATEトリガを他のテーブルで参照されるテーブルに作成することです。 トリガ引数は、この関数が検査を実行しなければならない参照テーブル数、参照キーが見つかった場合の動作(cascade — 参照行を削除、restrict — 参照キーが存在する場合トランザクションをアボート、setnull —参照キーフィールドをNULLに設定)、プライマリ/一意キーを形成するトリガを発行したテーブルの列名、参照テーブルの名前と列名(最初の引数で指定された数のテーブル分繰り返す)です。 プライマリ/一意キー列はNOT NULLと指定されていなければならず、また、一意性インデックスを持つべきであることに注意してください。

refint.exampleに例があります。

F.39.2. timetravel — 時間旅行を実装する関数

かなり前にPostgreSQLは各タプルで挿入時間、削除時間を保持する時間旅行機能が組み込まれました。 これをこれらの関数を使用して模擬することができます。 これらの関数を使用するためには、abstime型の、タプルの挿入日付(start_date)および変更/削除日付(stop_date)を格納するために2つの列をテーブルに追加しなければなりません。

CREATE TABLE mytab (
        ...             ...
        start_date      abstime,
        stop_date       abstime
        ...             ...
);

この列には好みの名前を付けることができますが、以下の説明ではstart_date、stop_dateを使用します。

新しく行が挿入される時、start_dateは通常現在時刻に、stop_dateはinfinityに設定されるはずです。 挿入されるデータにおけるこれらの列がNULLの場合、トリガは自動的にこれらの値を置き換えます。 一般的には、これらの列に非NULLのデータを明示的に挿入することは、ダンプデータの再ロードを行う時にしかないはずです。

stop_dateがinfinityのstop_dateを持つタプルは"現在有効"で、変更可能です。 トリガが防止するため、有限のstop_dateを持つタプルを変更することはできません。 (変更する必要がある場合は、以下のように時間旅行を無効にすることができます。)

変更可能な行では、更新時、更新されようとしているタプルのstop_dateのみが(現在時刻に)変更され、変更されたデータを持った新しいタプルが挿入されます。 この新しいタプルのstart_dateは現在時刻となり、stop_dateはinfinityになります。

削除では実際にタプルの削除は行われず、そのstop_dateが現在時刻になります。

"現在有効"なタプルを問い合わせるには、問い合わせのWHERE条件にstop_date = 'infinity'を含めてください。 (これをビューに組み込もうと考えるかもしれません。) 同様に、start_dateとstop_dateに適切な条件を付けることで任意の時点で有効だったタプルを問い合わせることもできます。

timetravel()は、こうした動作をサポートする、一般的なトリガ関数です。 時間旅行を行うテーブル毎にこの関数を使用したBEFORE INSERT OR UPDATE OR DELETEトリガを作成してください。 2つのトリガ引数で、start_dateとstop_date列の実際の名前を指定してください。 省略可能ですが、1から3つの引数を追加して指定することもできます。 これらはtext型の列を参照しなければなりません。 トリガは現在のユーザ名を、INSERT時に最初の列、UPDATE時に2番目の列、DELETE時に3番目の列に格納します。

set_timetravel()により、テーブル単位で時間旅行を有効または無効にすることができます。 set_timetravel('mytab', 1)mytabテーブルの時間旅行を有効にします。 set_timetravel('mytab', 0)mytabテーブルの時間旅行を無効にします。 時間旅行が無効な時、start_dateとstop_date列を自由に変更することができます。 有効状態は現在のデータベースセッション内で局所的な状態であることに注意してください。 新規セッションでは常に、すべてのテーブルの時間旅行は有効状態で始まります。

get_timetravel()は、状態変更を行うことなく、時間旅行の状態を返します。

timetravel.exampleに例が存在します。

F.39.3. autoinc — フィールド自動増分用の関数

autoinc()は、整数型フィールドにシーケンスの次の値を格納するトリガです。 これは、組み込みの"連番列"機能と一部重複しますが、同一ではありません。 autoinc()は挿入時に別のフィールド値に置き換える試みを上書きし、さらに省略可能ですが、更新時にフィールドを増加させるために使用することもできます。

使用方法は、この関数を使用するBEFORE INSERT(または BEFORE INSERT OR UPDATE)トリガを作成することです。 2つのトリガ引数、変更する整数型列の名前と値を生み出すシーケンスオブジェクトの名前を指定します。 (実際、自動増分列を複数更新したい場合、これらの名前の組み合わせを任意の数指定することができます。)

autoinc.exampleに例があります。

F.39.4. insert_username — 誰がテーブルを変更したかを追跡する関数

insert_username()は現在のユーザ名をテキスト型のフィールドに格納するトリガです。 これはテーブル内のある行を最後に変更したユーザを追跡する際に有用です。

使用方法は、この関数を使用するBEFORE INSERTUPDATEまたはその両方のトリガを作成することです。 1つのトリガ引数、変更するテキスト型の列の名前を指定してください。

insert_username.exampleに例があります。

F.39.5. moddatetime — 最終更新時刻を追跡する関数

moddatetime()は現在時刻をtimestamp型のフィールドに格納するトリガです。 これは、テーブル内のある行の最終更新時刻を追跡する際に有用です。

使用方法は、この関数を使用するBEFORE UPDATEトリガを作成することです。 1つのトリガ引数、変更する列名を指定してください。 この列はtimestamp型またはtimestamp with time zone型でなければなりません。

moddatetime.exampleに例があります。