Specifications of QDBM for Perl (Japanese)
Author: Mikio Hirabayashi
Description: specifications of Perl API of QDBM
Keywords: QDBM, Perl, Depot, Curia, Villa

# QDBM付属Perl用API仕様書

Copyright (C) 2000-2006 Mikio Hirabayashi
Last Update: Thu, 26 Oct 2006 15:00:20 +0900
[API] [English]

## 目次

1. 概要
2. インストール
3. サンプルコード
4. バグ

## 概要

QDBMにはPerl言語用のAPIがある。QDBMの基本APIと拡張APIと上級APIの関数群をPerlのクラス機構を用いてカプセル化したものである。C言語のAPIをXS言語を介して呼び出すように実装されている。データベースを扱うには、メソッドを明示的に呼び出す方法と、ハッシュにタイする方法がある。

メソッドを明示的に利用する場合、クラス `Depot' か `Curia' か `Villa' のコンストラクタ `new' を呼び出してデータベースを開き、その戻り値のオブジェクトをハンドルにする。データベースを閉じるにはメソッド `close' を呼ぶ。明示的にデータベースを閉じないでインスタンスが破棄される場合は、デストラクタによってデータベースが閉じられる。メソッド `put' はレコードを追加するために用いる。メソッド `out' はレコードを削除するために用いる。メソッド `get' はレコードを検索するために用いる。その他にも、C言語のAPIとほぼ同じ操作を利用することができる。

ハッシュにタイする場合、`tie' 関数の第三引数以降にコンストラクタと同様の引数を与える。タイした以後はそのハッシュに対する操作はデータベースへの操作とみなされる。データベースを閉じるには `untie' 関数を用いる。

データベースに格納するレコードのキーと値は文字列として扱われるが、バイナリデータをそのまま格納することも可能である。`Depot' はファイルを用いてハッシュデータベースを実現し、`Curia' はディレクトリと複数のファイルを用いてハッシュデータベースを実現し、`Villa' はファイルを用いてB+木データベースを実現する。`Depot' は最も高速である。`Curia' は最もスケーラブルである。`Villa' はカーソルによって順序に基づく参照を可能にする。

APIの詳細に関しては、サブディレクトリ `plapidoc' の文書を参照すること。

## インストール

Perlの5.6.0以降のバージョンがインストールされ、QDBMが `/usr/local' 以下にインストールされていることが必要である。

インストール作業は、サブディレクトリ `perl' をカレントディレクトリにして行う。

    cd perl

ビルド環境を設定する。

    ./configure

プログラムをビルドする。

    make

プログラムの自己診断テストを行う。

    make check

プログラムをインストールする。作業は `root' ユーザで行う。

    make install

一連の作業が終ると、Perlのインストールディレクトリに応じた適当な場所に `Depot.so'、`Depot.pm' 、`Curia.so' 、`Curia.pm' 、`Villa.so' 、`Villa.pm' 等のライブラリがインストールされ、コマンド `pldptest' と `plcrtest' と `plvltest' が `/usr/local/bin' にインストールされる。

アンインストールするには、`./configure' をした後の状態で以下のコマンドを実行する。作業は `root' ユーザで行う。

    make uninstall

## サンプルコード

名前と対応させて電話番号を格納し、それを検索するアプリケーションのサンプルコードを以下に示す。

    use Depot;

    use constant NAME => "mikio";
    use constant NUMBER => "000-1234-5678";
    use constant DBNAME => "book";

    sub main {
        my($depot, $val);

        # データベースを開く
        if(!($depot = new Depot(&DBNAME, Depot::OWRITER | Depot::OCREAT))){
            printf(STDERR "new failed: %s\n", $Depot::errmsg);
            return 1;
        }

        # レコードを格納する
        if(!$depot->put(&NAME, &NUMBER)){
            printf(STDERR "put failed: %s\n", $Depot::errmsg);
        }

        # レコードを取得する
        if(!($val = $depot->get(&NAME))){
            printf(STDERR "get failed: %s\n", $Depot::errmsg);
        } else {
            printf("Name: %s\n", &NAME);
            printf("Number: %s\n", $val);
        }

        # データベースを閉じる
        if(!$depot->close()){
            printf(STDERR "close failed: %s\n", $Depot::errmsg);
            return 1;
        }

        return 0;
    }

    exit(main());

上記の例をタイ関数を用いて書き直した例を以下に示す。

    use Depot;

    use constant NAME => "mikio";
    use constant NUMBER => "000-1234-5678";
    use constant DBNAME => "book";

    sub main {
        my(%hash, $val);

        # データベースを開く
        if(!tie(%hash, "Depot", &DBNAME, Depot::OWRITER | Depot::OCREAT)){
            printf(STDERR "tie failed: %s\n", $Depot::errmsg);
            return 1;
        }

        # レコードを格納する
        if(!($hash{&NAME} = &NUMBER)){
            printf(STDERR "store failed: %s\n", $Depot::errmsg);
        }

        # レコードを取得する
        if(!($val = $hash{&NAME})){
            printf(STDERR "fetch failed: %s\n", $Depot::errmsg);
        } else {
            printf("Name: %s\n", &NAME);
            printf("Number: %s\n", $val);
        }

        # データベースを閉じる
        if(!untie(%hash)){
            printf(STDERR "untie failed: %s\n", $Depot::errmsg);
            return 1;
        }

        return 0;
    }

    exit(main());

`Villa' クラスを用いて文字列の前方一致検索を行う例を以下に示す。

    use Villa;

    use constant DBNAME => "words";
    use constant PREFIX => "apple";

    sub main {
        my($villa, $key, $val);

        # データベースを開く
        if(!($villa = new Villa(&DBNAME, Villa::OWRITER | Villa::OCREAT))){
            printf(STDERR "new failed: %s\n", $Villa::errmsg);
            return 1;
        }

        # レコードを格納する
        if(!$villa->put("applet", "little application", Villa::DDUP) ||
           !$villa->put("aurora", "polar wonderwork", Villa::DDUP) ||
           !$villa->put("apple", "delicious fruit", Villa::DDUP) ||
           !$villa->put("amigo", "good friend", Villa::DDUP) ||
           !$villa->put("apple", "big city", Villa::DDUP)){
            printf(STDERR "put failed: %s\n", $Villa::errmsg);
        }

        # カーソルを候補の先頭に置く
        $villa->curjump(&PREFIX);

        # カーソルを走査する
        while($key = $villa->curkey()){
            my($prefix) = &PREFIX;
            ($key =~ m/^$prefix/) || last;
            $val = $villa->curval();
            printf("%s: %s\n", $key, $val);
            $villa->curnext();
        }

        # データベースを閉じる
        if(!$villa->close()){
            printf(STDERR "close failed: %s\n", $Villa::errmsg);
            return 1;
        }

        return 0;
    }

    exit(main());

## バグ

今のところ、AnyDBM_Fileの仲間ではない。

もしもPerlハッカー達の手にかかれば、より効率的な実装がなされるだろう。

インタフェースを簡潔にするため、Perl用のCuriaにはラージオブジェクトを扱う機能がなく、Perl用のVillaの比較関数にはユーザ定義関数を指定できない。