# Specification of QDBM for C++

Copyright (C) 2000-2003 Mikio Hirabayashi
Last Update: Fri, 04 Apr 2003 00:48:37 +0900
[API][English] [Home]

## Table of Contents

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

## 概要

QDBMにはC++言語用のAPIがある。QDBMの基本APIと拡張APIの関数群をC++のクラス機構を用いてカプセル化し、かつスレッドセーフにしたものである。

基本APIはファイルを用いてデータベースを実現する。クラス `Depot' のコンストラクタによってデータベースファイルが開かれる。データベースを閉じるにはメンバ関数 `close' を呼ぶ。明示的にデータベースを閉じないでDepotのインスタンスが破棄される場合は、デストラクタによってデータベースが閉じられる。メンバ関数 `put' はレコードを追加するために用いる。メンバ関数 `out' はレコードを削除するために用いる。メンバ関数 `get' はレコードを検索するために用いる。その他にも、C言語の基本APIとほぼ同じ操作を利用することができる。各メンバ関数はエラー時にクラス `Depot_error' のインスタンスを投げる。

拡張APIはディレクトリと複数のファイルを用いてデータベースを実現する。クラス `Curia' のコンストラクタによってデータベースファイルが開かれる。データベースを閉じるにはメンバ関数 `close' を呼ぶ。明示的にデータベースを閉じないでDepotのインスタンスが破棄される場合は、デストラクタによってデータベースが閉じられる。メンバ関数 `put' はレコードを追加するために用いる。メンバ関数 `out' はレコードを削除するために用いる。メンバ関数 `get' はレコードを検索するために用いる。ラージオブジェクトを扱うこともできる。その他にも、C言語の拡張APIとほぼ同じ操作を利用することができる。各メンバ関数はエラー時にクラス `Curia_error' のインスタンスを投げる。

クラス `Depot' とクラス `Curia' はともにクラス `ADBM' の派生クラスである。このクラスはUNIX標準のDBMと同様の機能を持つデータベースマネージャを抽象化したインタフェースであり、純粋仮想関数の宣言のみを行う。各メンバ関数はエラー時にクラス `DBM_error' のインスタンスを投げる。このフレームワークでは、レコードのキーや値はクラス `Datum' として表現される。`Datum' のインスタンスはデータ領域のポインタとそのサイズを持つ。３つのAPIから適切なものを選択する際には、実行効率を重視するなら `Depot' を、スケーラビリティを重視するなら `Curia' を、エレガンスと保守性を重視するなら `ADBM' を選ぶべきであろう。

APIの詳細に関しては、サブディレクトリ `xapidoc' の文書と各ヘッダファイルを参照すること。

## インストール

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

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

ビルド環境を設定する。

    ./configure

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

    make

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

    make check

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

    make install

一連の作業が終ると、ヘッダファイル `xdepot.h' と `xcuria.h' と `xadbm.h' が `/usr/local/include' に、ライブラリ `libxqdbm.a' が `/usr/local/lib' に、コマンド `xdptest' と `xcrtest' が `/usr/local/bin' にインストールされる。

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

    make uninstall

Windows（Cygwin）にインストールする場合、以下の手順に従う。

ビルド環境を設定する。

    ./configure

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

    make win

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

    make check

プログラムをインストールする。なお、アンインストールする場合は `make uninstall-win' とする。

    make install-win

Windowsでは、静的ライブラリ `libxqdbm.a' の代わりにインポートライブラリ `libxqdbm.dll.a' が生成され、さらにダイナミックリンクライブラリ `xqdbm.dll' が生成される。`xqdbm.dll' は `C:\WINNT\SYSTEM32' のようなシステムディレクトリにインストールされる。

## サンプルコード

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

    #include <xdepot.h>
    #include <cstdlib>
    #include <iostream>

    using namespace std;
    using namespace qdbm;

    const char* NAME = "mikio";
    const char* NUMBER = "000-1234-5678";
    const char* DBNAME = "book";

    int main(int argc, char** argv){
      try {

        // データベースを開く
        Depot depot(DBNAME, Depot::OWRITER | Depot::OCREAT);

        // レコードを格納する
        depot.put(NAME, -1, NUMBER, -1);

        // レコードを検索する
        char* val = depot.get(NAME, -1);
        cout << "Name: " << NAME << endl;
        cout << "Number: " << val << endl;
        free(val);

        // データベースを閉じる
        depot.close();

      } catch(Depot_error& e){
        cout << e.message() << endl;
        return 1;
      }
      return 0;
    }

上記の例を `ADBM' クラスを用いて書き直した例を以下に示す。

    #include <xadbm.h>
    #include <xdepot.h>
    #include <iostream>

    using namespace std;
    using namespace qdbm;

    const char* NAME = "mikio";
    const char* NUMBER = "000-1234-5678";
    const char* DBNAME = "book";

    int main(int argc, char** argv){
      try {

        // データベースを開く
        Depot depot(DBNAME, Depot::OWRITER | Depot::OCREAT);
        ADBM& dbm = depot;

        // レコードを準備する
        Datum key(NAME);
        Datum val(NUMBER);

        // レコードを格納する
        dbm.storerec(key, val);

        // レコードを検索する
        Datum* res = dbm.fetchrec(key);
        cout << "Name: " << NAME << endl;
        cout << "Number: " << res->ptr() << endl;
        delete res;

        // データベースを閉じる
        dbm.close();

      } catch(DBM_error& e){
        cout << e.message() << endl;
        return 1;
      }
      return 0;
    }

C++用APIを利用したプログラムをビルドするには、ライブラリ `libxqdbm.a' をリンク対象に加える必要がある。また、例外を扱うために、`g++' コマンドに `-fexceptions' オプションを加える必要がある。例えば、`sample.cc' から `sample' を作るには、以下のようにビルドを行う。

    g++ -I/usr/local/include -fexceptions -o sample sample.cc -L/usr/local/lib -lxqdbm -lqdbm

## バグ

ひとつのプロセスで複数のデータベースファイルを同時に利用することは可能であるが、同じデータベースファイルの複数のハンドルを利用してはならない。ひとつのデータベースを複数のスレッドで利用する場合には、メインスレッドで生成したハンドルを他のスレッドに渡せばよい。

GCCの現在のバージョン（3.2.2）は共有オブジェクトのコードから投げた例外を扱えないので、C++用APIは共有オブジェクトを提供できない。

一般的なオブジェクトを直列化してデータベースに格納する仕組みはないので、必要ならば、`Datum' クラスを拡張してその仕組みを作ってほしい。