他のバージョンの文書 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

17.6. 演算子とサポートルーチンの作成

これでアクセスメソッドと演算子クラスができました。次に、演算子の セットが必要になります。演算子を定義する処理はChapter 14で説明しました。 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;

ここで重要なことがいくつかあります。

ファイルの最後のルーチンは、 pg_amテーブルの amsupport 列について説明したときに出てきた "サポートルーチン"です。これは後に使います。今のところは無視します。

これで演算子を定義する準備ができました。

CREATE OPERATOR = (
     leftarg = complex, rightarg = complex,
     procedure = complex_abs_eq,
     restrict = eqsel, join = eqjoinsel
         );

ここで重要なのは、プロシージャ名(つまり上記で定義されるC 関数)と制約と結合選択関数です。例で使われている選択関数をただ使って下さい complex.sourceを参照)。これらは「より小さい」「等しい」そして「以上」の場合に使われる関数とは違うことに注意して下さい。これらが供給されなければ、オプティマイザはインデックスを効果的に利用できません。

次のステップはこれらの演算子の項目をpg_amop リレーションに追加することです。そうするためには、上記で定義したばかりの演算子の OID が必要です。ここでは二つのcomplex型をオペランドとして取る全ての演算子の名前を検索し、必要なものを選択します。

SELECT o.oid AS opoid, o.oprname
    INTO TEMP TABLE complex_ops_tmp
    FROM pg_operator o, pg_type t
    WHERE o.oprleft = t.oid and o.oprright = t.oid
      and t.typname = 'complex';

 opoid  | oprname
--------+---------
 277963 | +
 277970 | <
 277971 | <=
 277972 | =
 277973 | >=
 277974 | >
(6 rows)

(ここでまた、OID 番号はほぼ確実に違ったものになるでしょう。)ここで重要な演算子は277970 から 277974 までの OID をもつものです。得られる値はシステムによって異なるでしょうから、以下ではその値に置き換えて下さい。ここでは SELECT 文で行います。

ここで、新しい演算子クラス用のpg_amop のエントリを挿入する準備ができました。このエントリは正確に、必要とする演算子の B-tree ストラテジ番号に関連づけられていなければなりません。「より小さい」演算子を挿入するコマンドは以下のようになります。

INSERT INTO pg_amop (amopclaid, amopstrategy, amopreqcheck, amopopr)
    SELECT opcl.oid, 1, false, c.opoid
        FROM pg_opclass opcl, complex_ops_tmp c
        WHERE
            opcamid = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
            opcname = 'complex_abs_ops' AND
            c.oprname = '<';

次に、2行目の 1 と最後の < を置き換えて、他の演算子についても実行して下さい。順番に注意して下さい。 "より小さい" は 1、"以下" は 2、 "等しい" は 3、 "以上" は 4、そして、 "より大きい" は 5 です。

amopreqcheck フィールドについてはここで説明しません。B-tree 演算子では常に偽にすべきです。

最後のステップはpg_amの説明で以前に説明された "サポートルーチン" の登録です。このサポートルーチンのOID はpg_amprocテーブルに格納され、演算子クラスのOIDとサポートルーチン番号がキーになっています。

まず始めに、この関数をPostgresに登録する必要があります(演算子ルーチンを実装したファイルの最後にこのルーチンを実装するCコードを入れたことを思い出してください) 。

CREATE FUNCTION complex_abs_cmp(complex, complex)
    RETURNS integer
    AS 'PGROOT/src/tutorial/complex'
    LANGUAGE C;

SELECT oid, proname FROM pg_proc
    WHERE proname = 'complex_abs_cmp';

  oid   |     proname
--------+-----------------
 277997 | complex_abs_cmp
(1 row)

(ここでまた、OIDが違っているでしょう。)

下記のように新しい行を追加することができます。

INSERT INTO pg_amproc (amopclaid, amprocnum, amproc)
    SELECT opcl.oid, 1, p.oid
        FROM pg_opclass opcl, pg_proc p
        WHERE
            opcamid = (SELECT oid FROM pg_am WHERE amname = 'btree') AND
            opcname = 'complex_abs_ops' AND
            p.proname = 'complex_abs_cmp';

これで終りです! これでcomplex 列のbtree インデックスを作って使用することが可能になったはずです。