上記のように 7 つの概念がありますが、ここでは、新しい演算子クラスを作成する有用な例を紹介します。 最初に、演算子のセットが必要になります。演算子を定義する処理はChapter 11で説明しました。Btrees 上の complex_abs_ops 演算子クラスでは、以下の演算子が必要です。
これらの関数を実装するコードは、PGROOT/src/tutorial/complex.cに格納され、PGROOT/src/tutorial/complex.so にコンパイルしたものとします。C コードの一部を以下に示します。
#define Mag(c) ((c)->x*(c)->x + (c)->y*(c)->y) bool complex_abs_eq(Complex *a, Complex *b) { double amag = Mag(a), bmag = Mag(b); return (amag==bmag); }
(このテキストでは、等価演算子のみを紹介していることに注意してください。他の 4 つの演算子は良く似ています。詳細は、 complex.c または complex.source をご覧ください。)
PostgreSQL に関数を登録するために下記のようにします。
CREATE FUNCTION complex_abs_eq(complex, complex) RETURNS boolean AS 'PGROOT/src/tutorial/complex' LANGUAGE C;
ここで重要なことがいくつかあります。
まず、complex 用の「より小さい」、「以下」、「等しい」、「以上」、 「より大きい」のための演算子が定義されようとしているということです。例えば、= という演算子は一つしかもつことが出来ず、両方のオペランドをcomplex 型とします。この場合complexに対してほかの演算子 = はありません。 しかしもし実用的なデータ型を構築するなら、多分 = は複素数の通常の等しいという演算になってほしいかと思います。その場合は、complex_abs_eq に対しなにか他の演算子名を使う必要があります。
二番目に、PostgreSQL の場合は、違った入力データ型であれば同じ名前の演算子を使うことができますが、C ではネームスペース内で一つのグローバルルーチンが使えるだけです。ですから C 関数は abs_eq のような単純な名前にするべきではありません。通常は C 関数名にデータ型名を入れておけば、他のデータ型の関数と衝突することもありません。
三番目に、関数abs_eqの PostgreSQL 名は、PostgreSQL が入力データ型によって同じ名前を持つ他の PostgreSQL 関数から区別してくれることを期待して作ることができます。ここでは例を簡単にするために、関数に C レベルと PostgreSQL レベルで同じ名前を与えます。
最後に、これらの演算子関数はブーリアンの値を返すことに注意して下さい。実際、インデックスアクセスメソッドストラテジとして定義した、全ての演算子は boolean 型を返さなければなりません。 ですので、これらは、インデックスが使用されるために、WHERE のトップレベルに現れなければなりません。 (一方で、サポート関数は、特定のアクセスメソッドが期待するものを何でも返します。 B-tree の比較関数の場合は、符号付き整数です。)
これで演算子を定義する準備ができました。
CREATE OPERATOR = ( leftarg = complex, rightarg = complex, procedure = complex_abs_eq, restrict = eqsel, join = eqjoinsel );
ここで重要なのは、プロシージャ名(つまり上記で定義されるC 関数)と制約と結合選択関数です。例で使われている選択関数をただ使って下さいcomplex.sourceを参照)。これらは「より小さい」「等しい」そして「以上」の場合に使われる関数とは違うことに注意して下さい。これらが供給されなければ、オプティマイザはインデックスを効果的に利用できません。
次のステップは、B-tree に必要な比較「サポートルーチン」の登録です。 これを実装するための C コードは、演算子プロシージャと同じファイルに入っています。
CREATE FUNCTION complex_abs_cmp(complex, complex) RETURNS integer AS 'PGROOT/src/tutorial/complex' LANGUAGE C;