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

35.15. 関連するオブジェクトを拡張としてパッケージ化

PostgreSQL への有用な拡張は通常、複数のSQLオブジェクトを含んでいます。 例えば、新しいデータ型は新しい関数、新しい演算子、おそらく新しいインデックス演算子クラスを必要とします。 これらのオブジェクトをすべて単一のパッケージとしてまとめることは、データベース管理を単純化するために役に立ちます。 PostgreSQL ではこうしたパッケージを 拡張 とよびます。 拡張を定義するためには、少なくとも、拡張のオブジェクトを作成するための SQL コマンドを含む スクリプトファイル 、拡張自身の数個の基本属性を指定する 制御ファイル が必要です。 また拡張がCコードを含む場合、通常Cコードで構築された共有ライブラリが存在します。 これらのファイルがあれば、単純な CREATE EXTENSION コマンドがそのオブジェクトをデータベース内に読み込みます。

拡張を使用する主な利点は、 SQL スクリプトを実行するだけでデータベースに "粗な" なオブジェクトの群をロードできることではなく、 PostgreSQL が拡張のオブジェクトをまとまったものと理解できることです。 単一の DROP EXTENSION コマンドでオブジェクトすべてを削除することができます(個々の "アンインストール" スクリプトを保守する必要はありません)。 もっと有用なことは、 pg_dump が拡張の個々のメンバオブジェクトを削除してはならないことを把握していることです。 代わりにダンプ内には CREATE EXTENSION コマンドだけが含まれます。 これは、古いバージョンよりも多くのまたは異なるオブジェクトを含む可能性がある、拡張の新しいバージョンへの移行を大きく単純化します。 しかし、こうしたダンプを新しいデータベースにロードする際には、拡張の制御ファイル、スクリプトファイル、その他のファイルが利用できるようにしておく必要があります。

PostgreSQL はユーザに、拡張全体を削除させる以外に、拡張内に含まれる個々のオブジェクトを削除させません。 また、拡張のメンバオブジェクトの定義を変更する(例えば関数では CREATE OR REPLACE FUNCTION を介して変更する)ことはできますが、変更した定義は pg_dump によりダンプされないことに留意してください。 こうした変更は通常、同時に拡張のスクリプトファイルにも同じ変更を行った場合のみ認識することができます。 (しかし後述するように設定データを持つテーブルに対しては特殊な準備があります。)

また拡張機構は、拡張に含まれるSQLオブジェクトの定義を調整するパッケージ調整スクリプトを準備しています。 例えば、拡張のバージョン1.1でバージョン1.0と比べて1つの関数を追加し、他の関数本体を変更する場合、拡張の作成者はこれらの2つの変更のみを行う 更新スクリプト を提供することができます。 そして ALTER EXTENSION UPDATE コマンドを使用して、これらの変更を適用し、指定されたデータベース内に実際にインストールされた拡張のバージョンが何かを記録します。

拡張のメンバとなり得るSQLオブジェクトの種類を ALTER EXTENSION で説明します。 拡張は1つのデータベースの中でのみ認識されますので、データベース、ロール、テーブル空間などデータベースクラスタ全体のオブジェクトは拡張のメンバにすることができないことに注意してください。 (拡張のスクリプトでこうしたオブジェクトを生成することは禁止されていませんが、作成したとしても、拡張の一部として記録されません。) また、テーブルは拡張のメンバになることができますが、インデックスなどそれに付随するオブジェクトは拡張の直接的なメンバとはみなされません。 もう一つの重要な点は、スキーマは拡張に属すことがありますがその逆はないということです。 拡張は非修飾名でいかなるスキーマの "の中に" も存在しません。 しかし、拡張のメンバオブジェクトはオブジェクトの型が適切であればスキーマに属します。 拡張が自身のメンバオブジェクトが属するスキーマを所有することは適切かも知れませんし、そうでないかも知れません。

35.15.1. 拡張のファイル

CREATE EXTENSION コマンドは各拡張に関して、拡張と同じ名前に .control という拡張子を持つファイル名である必要がある、制御ファイルに依存します。 また、このファイルはインストレーションの SHAREDIR/extension ディレクトリ内に存在しなければなりません。 また少なくとも1つの、 extension -- version .sql という命名規約(例えば foo 拡張のバージョン 1.0 では foo--1.0.sql )に従った SQL スクリプトファイルが存在しなければなりません。 デフォルトでは、このスクリプトファイルも SHAREDIR/extension ディレクトリに格納されますが、制御ファイルでスクリプトファイルを別のディレクトリに指定することができます。

拡張の制御ファイルのファイル書式は postgresql.conf ファイルと同じです。 すなわち、 parameter_name = value という代入を1行当たり1つ記述します。 空行および # から始まるコメントが許されます。 単一の単語または数字ではない値にはすべて引用符で確実にくくってください。

制御ファイルは以下のパラメータを設定することができます。

directory ( string )

拡張の SQL スクリプトファイルを含むディレクトリです。 絶対パスで指定されていない限り、この名前はインストレーションの SHAREDIR ディレクトリからの相対バスになります。 デフォルトの動作は directory = 'extension' と指定した場合と同じです。

default_version ( string )

拡張のデフォルトのバージョン( CREATE EXTENSION でバージョン指定がない場合にインストールされるバージョン)です。 これは省略することができますが、その場合 VERSION オプションがない CREATE EXTENSION は失敗します。 ですので通常省略しようとは思わないでしょう。

comment ( string )

拡張に関するコメント(任意の文字列)です。 この他の方法として、スクリプトファイル内で COMMENT コマンドを使用してコメントを設定することができます。

encoding ( string )

スクリプトファイルで使用される文字セット符号化方式です。 スクリプトファイルに何らかの非ASCII文字が含まれる場合に指定しなければなりません。 指定がなければ、ファイルはデータベース符号化方式であると仮定されます。

module_pathname ( string )

このパラメータの値でスクリプトファイル内の MODULE_PATHNAME の出現箇所が置換されます。 設定されていない場合は置換は行われません。 通常これは、スクリプトファイル内で共有ライブラリの名前を直接書き込む必要がなくなるように $libdir/ shared_library_name に設定され、C言語関数では CREATE FUNCTION コマンド中で MODULE_PATHNAME を使用します。

requires ( string )

拡張が依存する拡張の名前のリストです。 例えば requires = 'foo, bar' です。 対象の拡張がインストールできるようになる前に、これらの拡張がインストールされていなければなりません。

superuser ( boolean )

このパラメータが true (デフォルト)の場合、スーパーユーザのみが拡張を作成または新しいバージョンに更新することができます。 false に設定されている場合は、インストレーション内でコマンドを実行するまたはスクリプトを更新するために必要な権限のみが必要とされます。

relocatable ( boolean )

拡張を最初に作成した後に拡張により含まれるオブジェクトを別のスキーマに移動することができる場合、拡張は 再配置可能 です。 デフォルトは false 、つまり、拡張は再配置可能ではありません。 詳しくは後で説明します。

schema ( string )

このパラメータは再配置可能ではない拡張に対してのみ設定することができます。 拡張が指名したスキーマのみにロードされ、他にはロードされないことを強制します。 詳しくは後で説明します。

主制御ファイル extension .control に加え、拡張は extension -- version .control という形の名前の副制御ファイルを持つことができます。 これらを提供する場合は、スクリプトファイルディレクトリに格納しなければなりません。 副制御ファイルは主制御ファイルと同じ書式に従います。 拡張の対応するバージョンをインストールまたは更新する時、副制御ファイル内で設定されるパラメータはいずれも、主制御ファイルを上書きします。 しかし directory および default_version パラメータは副制御ファイルで設定することはできません。

拡張の SQL スクリプトファイルにはトランザクション制御コマンド( BEGIN COMMIT など)およびトランザクションブロックの内側で実行することができないコマンド( VACUUM など)を除く任意のSQLコマンドを含めることができます。 スクリプトファイルが暗黙的にトランザクションブロック内で実行されるためです。

拡張の SQL スクリプトファイルには、 \echo から始まる行を含めることができます。 この行は拡張の機構では無視されます(コメントとして扱われます)。 これは、このスクリプトが CREATE EXTENSION (後述のスクリプト例を参照)ではなく psql に渡された場合にエラーを発生するために一般的に使用するために用意されたものです。 これがないと、ユーザは間違って拡張としてではなく、 "まとまっていまい" オブジェクトとして拡張の内容をロードしてしまい、復旧が多少困難な状態になる可能性があります。

スクリプトファイルは指定した符号化方式で認められる任意の文字を含めることができますが、 PostgreSQL が制御ファイルの符号化方式が何かを把握する方法がありませんので、制御ファイルにはASCII文字のみを含めなければなりません。 実際には、拡張のコメントに非ASCII文字を含めたい場合にのみ、これが問題になります。 このような場合には、制御ファイルの comment を使用せず、代わりにコメントを設定するためにスクリプトファイル内で COMMENT ON EXTENSION を使用することを勧めます。

35.15.2. 拡張の再配置性

ユーザは拡張に含まれるオブジェクトを拡張の作成者が考えていたスキーマとは別のスキーマにロードしたいとよく考えます。 再配置性に関して3つのレベルがサポートされます。

  • 完全な再配置可能な拡張は、いつでも、データベースにロードされた後であっても、他のスキーマに移動させることができます。 これは、自動的にすべてのメンバオブジェクトを新しいスキーマに名前を変更する、 ALTER EXTENSION SET SCHEMA を用いて行います。 通常これは、拡張がオブジェクトが含まれるスキーマが何かに関して内部的な仮定を持たない場合のみ可能です。 また、拡張のオブジェクト(手続き言語など何らかのスキーマに属さないオブジェクトは無視して)はすべて最初に1つのスキーマ内に存在しなければなりません。 制御ファイル内で relocatable = true と設定することで、完全な再配置可能と印付けます。

  • 拡張はインストール処理の間再配置可能ですが、その後再配置することはできません。 通常これは、拡張のスクリプトファイルが、SQL関数用の search_path 属性の設定など、対象のスキーマを明示的に参照する必要がある場合です。 こうした拡張では、制御ファイルで relocatable = false と設定し、スクリプトファイル内で対象のスキーマを参照するために @extschema@ を設定してください。 この文字列の出現箇所はすべて、スクリプトが実行される前に、実際の対象のスキーマ名に置換されます。 ユーザは CREATE EXTENSION SCHEMA オプションを使用して対象のスキーマを設定することができます。

  • 拡張が再配置をまったくサポートしない場合、制御ファイルで relocatable = false を設定し、かつ、 schema を意図している対象スキーマの名前に設定してください。 これは、制御ファイル内で指定されたスキーマと同じ名前が指定されていない限り、 CREATE EXTENSION SCHEMA オプションの指定を阻止します。 この選択は通常、拡張が @extschema@ を使用して置き換えることができないスキーマ名について内部的な仮定を持つ場合に必要です。 @extschema@ 置換機構はこの場合でも使用することができますが、スキーマ名が制御ファイルによって決定されますので、用途は限定されます。

すべての場合において、スクリプトファイルは対象のスキーマを指し示すようにあらかじめ設定した search_path を用いて実行されます。 つまり CREATE EXTENSION は以下と同じことを行います。

SET LOCAL search_path TO @extschema@;

これによりスクリプトファイルで作成されるオブジェクトを対象のスキーマ内に格納することができます。 スクリプトファイルは要望に応じて search_path を変更することができますが、一般的には望まれません。 CREATE EXTENSION の実行後、 search_path は以前の設定に戻されます。

対象のスキーマは制御ファイル内の schema パラメータがあればこのパラメータにより決定されます。 このパラメータがなければ、 CREATE EXTENSION SCHEMA があればこの値で決まり、これ以外の場合は現在のデフォルトのオブジェクト生成用スキーマ(呼び出し元の search_path の最初のもの)になります。 制御ファイルの schema パラメータが使用される時、対象のスキーマが存在しない場合は作成されますが、これ以外の2つの場合ではすでに存在しなければなりません。

何らかの事前に必要な拡張が制御ファイル内の requires に列挙されていた場合、それらの対象スキーマが search_path の初期設定に追加されます。 これにより新しい拡張のスクリプトファイルからそれらのオブジェクトが可視になります。

再配置不可能な拡張は複数スキーマにまたがるオブジェクトを含めることができますが、通常、外部使用を意図したオブジェクトはすべて単一スキーマに格納することが望まれます。 この単一スキーマが拡張の対象のスキーマとみなされます。 こうした調整は依存する拡張を作成する間、デフォルトの search_path 設定を都合に合わせて扱います。

35.15.3. 拡張設定テーブル

一部の拡張は、拡張をインストールした後でユーザにより追加または変更される可能性があるデータを持つ設定テーブルを含みます。 通常、テーブルが拡張の一部である場合、テーブル定義もその内容も pg_dump によりダンプされません。 しかしこの振舞いは設定テーブルの場合望まれません。 ユーザによってなされたデータ変更はダンプ内に含まれなければなりません。 さもないとダンプしリストアした後で拡張の動作が変わってしまいます。

この問題を解消するために、拡張のスクリプトファイルでは設定テーブルとして作成されるテーブルに印を付け、 pg_dump にテーブルの内容をダンプに含める(定義は含まれません)ようにさせることができます。 このためには、以下の例のようにテーブルを作成した後に pg_extension_config_dump(regclass, text) 関数を呼び出してください。

CREATE TABLE my_config (key text, value text);

SELECT pg_catalog.pg_extension_config_dump('my_config', '');

任意数のテーブルをこの方法で印付けることができます。

pg_extension_config_dump の第2引数が空文字列である場合、テーブルのすべての内容が pg_dump によりダンプされます。 これは、拡張のスクリプトによって作成された初期段階においてテーブルが空である場合のみ正しいものです。 テーブルの中で初期データとユーザが提供したデータが混在する場合、 pg_extension_config_dump の第2引数においてダンプすべきデータを選択する WHERE 条件を提供します。 以下に例を示します。

CREATE TABLE my_config (key text, value text, standard_entry boolean);

SELECT pg_catalog.pg_extension_config_dump('my_config', 'WHERE NOT standard_entry');

このようにした後、拡張のスクリプトで作成される行のみで standard_entry が確実に真になるようにします。

初期状態で提供される行がユーザによって変更されるようなもっと複雑な状況では、設定テーブルに対するトリガを作成して、変更された行が正しく印付けられることを確実にするように取り扱うことができます。

pg_extension_config_dump を再度呼び出すことにより、設定テーブルに関連付いたフィルタ条件を変更することができます。 (通常これは拡張の更新スクリプト内で役に立つでしょう。) 設定ファイルからテーブルを取り除くように印付ける方法は、 ALTER EXTENSION ... DROP TABLE を用いてテーブルを拡張から分離するしかありません。

35.15.4. 拡張の更新

拡張機構の1つの利点は、拡張のオブジェクトを定義するSQLコマンドの更新を簡便に管理する方法を提供していることです。 これは、拡張のインストール用スクリプトのリリース版それぞれにバージョン名称またはバージョン番号を関連付けることで行われます。 さらに、ユーザにあるバージョンから次のバージョンへ動的にデータベースを更新させることができるようにしたい場合、あるバージョンから次のバージョンまでの間に行われる必要な変更を行う 更新スクリプト を提供しなければなりません。 更新スクリプトは extension -- oldversion -- newversion .sql というパターンに従った名前(例えば、 foo--1.0--1.1.sql foo 拡張のバージョン 1.0 からバージョン 1.1 に変更するコマンドを含みます。)を持たなければなりません。

適切な更新スクリプトが利用可能である場合、 ALTER EXTENSION UPDATE コマンドはインストール済みの拡張を指定した新しいバージョンへ更新します。 更新スクリプトは、 CREATE EXTENSION がインストール用スクリプト向けに提供する環境と同じ環境で実行されます。 具体的には search_path は同じ方法で設定され、スクリプトにより作成される新しいオブジェクトはすべて自動的に拡張に追加されます。

拡張が副制御ファイルを持つ場合、更新スクリプトで使用される制御パラメータは、スクリプトの対象の(新しい)バージョンに関連付けされたものになります。

更新機構を使用して、オブジェクトの "粗" 集合から拡張に変換するという、特別かつ重大な状況を解消することができます。 拡張機構が PostgreSQL に(9.1で)追加されるようになる前では、パッケージ化されずに単に詰めあわされたオブジェクトを作成する拡張モジュールを多くのユーザが作成していました。 こうしたオブジェクトを持つデータベースが存在する場合、どのようにすればこれらのオブジェクトを適切にパッケージ化された拡張に変換できるでしょうか? 削除した後で普通に CREATE EXTENSION を行うことも1つの方法ですが、オブジェクトに依存関係がある(例えば拡張により作成されたデータ型のテーブル列が存在する場合など)場合は好まれません。 こうした状況を解消する方法は、空の拡張を作成し、 ALTER EXTENSION ADD を使用して、既存のオブジェクトそれぞれを拡張に関連づけ、最後にパッケージ化されていないリリースに存在しないが現在のバージョンの拡張には存在する新しいオブジェクトを作成するという方法です。 CREATE EXTENSION FROM old_version オプションでこの状況をサポートします。 この場合、通常のインストール用スクリプトは実行されず、代わりに extension -- old_version -- target_version .sql という名前の更新スクリプトが実行されるようになります。 old_version として使用するダミーのバージョン名の選択は拡張の作成者に任せられていますが、 unpackaged がよく使われる規約です。 拡張形式に更新できるようにしたい過去のバージョンが複数存在する場合、それらを識別できるように複数のダミーバージョン番号を使用していください。

ALTER EXTENSION は、要求される更新を実現するために更新スクリプトを連続して実行することができます。 例えば foo--1.0--1.1.sql foo--1.1--2.0.sql のみが利用可能であるとすると、現在 1.0 がインストールされている時にバージョン 2.0 への更新が要求された場合、 ALTER EXTENSION はこれらを順番に適用します。

PostgreSQL はバージョン名称の特性についてまったく仮定を行いません。 例えば 1.0 の次が 1.1 であるかどうかを把握しません。 これは利用可能なバージョン名をかみ合わせ、もっとも少ない数の更新スクリプトを適用するために必要な経路を続けるだけです。 (バージョン名には、 -- を含まず先頭または最後に - が付かなければ、任意の文字を取ることができます。)

"ダウングレード" スクリプトを提供することが便利な場合があります。 例えば foo--1.1--1.0.sql は、バージョン 1.1 に関連した変更を基に戻すことができます。 この場合、ダウングレードスクリプトがより短いパスを生成するために、予期せず適用されてしまう可能性に注意してください。 複数のバージョンをまたがって更新する "近道" 更新スクリプトと近道の開始バージョンへのダウングレードスクリプトが存在する場合に危険性があります。 ダウングレードしてから近道となる更新スクリプトを実行する方が、バージョンを1つずつ進めるよりも少ない処理で済んでしまうかもしれません。 ダウングレードスクリプトが取り返しがつかないオブジェクトを何か削除してしまう場合、望まない結果になってしまいます。

想定外の更新経路かどうかを検査するためには、以下のコマンドを使用してください。

SELECT * FROM pg_extension_update_paths('

extension_name

');

これは指定した拡張の個々の既知のバージョン名の組み合わせをそれぞれ、元のバージョンから対象のバージョンへ進む時に取られる更新経路順、またはもし利用できる更新経路がなければ NULL を付けて、表示します。 経路は -- を区切り文字として使用したテキスト形式で表示されます。 配列形式の方が良ければ regexp_split_to_array(path,'--') を使用することができます。

35.15.5. 拡張の例

ここでは、 SQL のみの拡張の完全な例を示します。 "k" "v" という名称の2つの要素からなる複合型であり、そのスロットには任意の型の値を格納することができるものです。 格納の際テキスト以外の値は自動的にテキストに変換されます。

pair--1.0.sql スクリプトファイルは以下のようになります。

-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION pair" to load this file. \quit

CREATE TYPE pair AS ( k text, v text );

CREATE OR REPLACE FUNCTION pair(anyelement, text)
RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair';

CREATE OR REPLACE FUNCTION pair(text, anyelement)
RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair';

CREATE OR REPLACE FUNCTION pair(anyelement, anyelement)
RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair';

CREATE OR REPLACE FUNCTION pair(text, text)
RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::pair;';

CREATE OPERATOR ~> (LEFTARG = text, RIGHTARG = anyelement, PROCEDURE = pair);
CREATE OPERATOR ~> (LEFTARG = anyelement, RIGHTARG = text, PROCEDURE = pair);
CREATE OPERATOR ~> (LEFTARG = anyelement, RIGHTARG = anyelement, PROCEDURE = pair);
CREATE OPERATOR ~> (LEFTARG = text, RIGHTARG = text, PROCEDURE = pair);

pair.control 制御ファイルは以下のようになります。

# pair extension
comment = 'A key/value pair data type'
default_version = '1.0'
relocatable = true

これらの2つのファイルを正しいディレクトリにインストールするためにメークファイルを作成する必要はほとんどありませんが、以下を含む Makefile を使用することができます。

EXTENSION = pair
DATA = pair--1.0.sql

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

このメークファイルは 項35.16 で説明する PGXS に依存します。 make install コマンドは制御ファイルとスクリプトファイルを pg_config で報告される正しいディレクトリにインストールします。

ファイルがインストールされた後、 CREATE EXTENSION コマンドを使用してオブジェクトを任意の特定のデータベースにロードしてください。


powered by SEO.CUG.NET