APR DBD

Apache HTTP Server 2.0 からは、APR (Apache Portable Runtime) というライブラリが Apache とは別に開発され、Apache HTTP Server は、その APR を土台として作られています。この APRは、OS間の差異を吸収するための関数や、プログラムを作成する上で便利な関数の集合体です。

APRはApache HTTP Serverにも同梱されていますが、別アーカイブとしても配布されており、それを入手して利用することもできます。

Apache HTTP Server 2.0系統の時には APR はまだバージョン1.0に達しておらず、2.0系統の最新版である 2.0.59 では 0.9.12 が同梱されていました。しかし、最新の安定板系列である2.2.3では1.2.7になっています。

APRには、基本的な関数群をまとめたAPR、付加的な「便利関数」をまとめたAPR-util、文字コードの変換を行なうためのAPR-iconvの3種類があり、それぞれが別アーカイブにまとめられて配布されています。

APRプロジェクトのホームページは http://apr.apache.org/ で、ここからソースコードを入手したり、ドキュメントを参照することができます。ただ、一部の関数群についてはサイト上にドキュメントが揃っていません。

本記事では、APR-utilのDBDモジュールについて簡単に紹介します。

APR DBD とは

APR DBD は APR-util ライブラリに含まれるモジュールで、バージョン1.2.1から追加されました。このモジュールは各種RDBMSへの接続や問い合わせを共通化されたAPIから利用できるようにするものです。

バージョン1.2.7では標準ではSQLite2、SQLite3、PostgreSQLをサポートしていますが、別途、「ドライバ」と呼ばれるコードを入手することで、MySQLも利用できます。別になっているのは、MySQLのドライバのライセンスがGPLであるため、ASFリリースはされていますが、開発版ではOracle対応のドライバもあります。MySQLのドライバは

http://apache.webthing.com/database/

から入手できます。このページには、DBDについての簡単な解説もあります。

APR DBDのAPI

DBDで、どのようなAPIが公開されているのかについては、2006.8.5現在、サイト上にはドキュメントが存在していません。しかし、ソースコードのapr_dbd.hを見れば、関数名と引数の説明を知ることができます。また、ソースコードを展開して、configureスクリプトを実行し、make doxを実行することで、doxygenによってドキュメントが自動生成されます。

% tar xzf apr-util-1.2.7.tar.gz
% cd apr-util-1.2.7
% ./configure --with-apr=/usr
% make dox
% ls docs/dox/html/

APR DBDサンプル

DBDを使って、簡単なサンプルを作成しました。説明のため、一切のエラー処理は省いてあります。

 #include <stdio.h>
 #include <stdlib.h>
 #include <apr_general.h>
 #include <apu.h>
 #include <apr_dbd.h>
 
 /* 利用するドライバの名前 (SQLite verion 3) */
 const char driver_name[] = "sqlite3";
 /* データベースに接続する際のパラメータ (SQLite3 の場合はファイル名) */
 const char params[]      = "msg.db";
 /* 実行するSELECT文 */
 const char stmt[]        = "SELECT id,author,subject FROM msg";
 
 int
 main(int argc, char const* const argv[], char const* const env[])
 {
 	apr_pool_t *pool;
 	const apr_dbd_driver_t *driver;
 	apr_dbd_t *handle;
 	apr_dbd_results_t *res;
 	apr_dbd_row_t *row;
 
 	/* APR を使用することを宣言 */
 	apr_app_initialize(&argc, &argv, &env);
 	/* root pool を作成 */
 	apr_pool_create(&pool, NULL);
 	/* DBD モジュールを初期化 */
 	apr_dbd_init(pool);
 	/* driver を指定 */
 	apr_dbd_get_driver(pool, driver_name, &driver);
 	/* データベースに接続 */
 	apr_dbd_open(driver, pool, params, &handle);
 	/* SELECT を実行 */
 	apr_dbd_select(driver, pool, handle, &res, stmt, 0);
 	/* 行を取得 */
 	while (apr_dbd_get_row(driver, pool, res, &row, -1) == 0) {
 		/* 各行から列を取得し、表示 */
 		printf("%s, %s, %s\n",
 		       apr_dbd_get_entry(driver, row, 0),
 		       apr_dbd_get_entry(driver, row, 1),
 		       apr_dbd_get_entry(driver, row, 2));
 	}
 	/* データベースを閉じる */
 	apr_dbd_close(driver, handle);
 	/* APR の利用を終了 */
 	apr_terminate();
 	return 0;
 }

これはデータベースを開いてSELECT文を実行し、返ってきた行の内容を表示するだけ、というものです。実行する前にあらかじめmsg.dbというデータベースを以下のSQLで作成する必要があります。

msg.sqlの内容:

CREATE TABLE msg (
 id            INTEGER PRIMARY KEY,
 author        TEXT NOT NULL,
 timestamp     INTEGER NOT NULL,
 subject       TEXT NOT NULL,
 body          TEXT NOT NULL
);

msg-data.sqlの内容:

 INSERT INTO msg (author,timestamp,subject,body)
       VALUES ('user1',1154698371,'test message','Hello, world');
 INSERT INTO msg (author,timestamp,subject,body)
       VALUES ('user2',1154698381,'test message 2','My name is John Smith');
 INSERT INTO msg (author,timestamp,subject,body)
       VALUES ('user3',1154698411,'test message 3','No news is good news');

データベース作成の手順 (Debian sid の場合):

 % sqlite3 msg.db
 SQLite version 3.3.5
 Enter ".help" for instructions
 sqlite> .read msg.sql
 sqlite> .read msg-data.sql
 sqlite> ^D
 % ls msg.db
 msg.db

Makefile:

 CFLAGS := $(shell pkg-config --cflags apr-util-1 apr-1)
 LDFLAGS := $(shell pkg-config --libs apr-util-1 apr-1)
 
 aprdbdtest: aprdbdtest.o
 aprdbdtest.o: aprdbdtest.c

コンパイルと実行:

 % make
 cc -laprutil-1 -lldap -llber -ldb-4.3 -lpq -lsqlite3 -lexpat -lapr-1 
    -luuid -lrt -lcrypt -lpthread -ldl    aprdbdtest.o   -o aprdbdtest
 % ./aprdbdtest
 1, user1, test message
 2, user2, test message 2
 3, user3, test message 3
 %

サンプルの解説

サンプルはかなり単純なのものです。ライブラリの初期化、データベースエンジンの指定(ドライバの取得)、データベースへの接続、SELECTによる問い合わせ、結果の利用、終了、という手順に従って進んでいます。

実際に利用するコードを書く場合には、各関数の返り値に留意し、エラー処理を実行する必要があります。apr_status_tを返す関数の場合は、APR_SUCCESSが返ってきたら成功、intを返すような関数の場合は0であれば成功、となっていたりしますので、make doxによって生成されたドキュメントを参照してください。

さて、APRの固有のことについて簡単に解説を加えておきます。

apr_app_initialize() は、アプリケーションの最初のほうで、APRライブラリを利用することを宣言するために必要なものです。実はUNIX環境ではapr_initialize()という関数を呼ぶのと等価ですが、他の環境(WindowsやNetware)ではさらに追加の処理が実行されます。

apr_pool_create() は、poolと呼ばれるものを初期化します。これはAPRにおいてメモリ管理を行うために必要な情報です。サーバとして動作するApache HTTP Serverではメモリの生成、開放というのは、メモリを食い潰したりするのを防ぐためにもかなり重要なのですが、poolはその手間を軽減してくれる便利なツールです。

poolを通じてメモリを取得すると、poolを破棄するだけで、そのpool経由で取得したメモリがすべて開放されます。また、複数のpoolを階層的に作成することができますので、処理の局面ごとに粒度の細かなメモリ管理ができます。

Apache HTTP Serverの場合は、プロセスの生成ごとに作られるpool、各リクエストごとに作られるpool、といったものが存在していたります。今回のサンプルでは一つのpoolで用が足りますので、それを作成しています。

apr_dbd_get_driver()では、どのデータベースエンジンを使うのか、を指定します。本サンプルではSQLite version 3を使うので、sqlite3という文字列を2つ目に指定しています。apr-util 1.2.7では、コンパイル時の設定にもよりますが、以下の4つが指定可能です。

取得したドライバは3つ目で指定した引数にセットされて返ります。

apr_dbd_openでは、データベースに接続します。3つ目の引数で接続するデータベースについての情報を渡す必要がありますが、これはデータベースエンジンごとに記述方法が違います。SQLite version3の場合は、データベースのファイルのファイル名を渡すだけでいいので簡単です。PostgreSQLの場合は、PQconnectdb()という、PostgreSQLのライブラリ関数の引数と同等ですので

 http://www.postgresql.jp/document/pg814doc/html/libpq.html#LIBPQ-CONNECT

などのマニュアルを参考にしてください。MySQLの場合は、

 "host=XXXX user=YYYY pass=ZZZZ dbname=DBNAME"

のような文字列を指定すれば良さそうです。この文字列を解析し、mysql_real_connect() に渡しています。他には port、sock、flags、fldsz といったパラーメータがあるみたいです。

 http://dev.mysql.com/doc/refman/4.1/ja/mysql-real-connect.html

を参考にしてください。接続したデータベースは、4つ目の引数にセットされます。

APIその他

これまでのサンプルでは省きましたが、prepared statement ももちろんサポートしています。apr_dbd_prepare()でprepared statementを作成し、apr_dbd_pselect()あるいはapr_dbd_pvselet()で値をbindしてSELECTを実行します。apr_dbd_pselect()では引数の個数と引数の配列を渡します。apr_dbd_pvselect()では可変引数を使用します。

また、SELECTのような値を返すSQL文以外ではapr_dbd_query()やapr_dbd_pquery()、apr_dbd_pvquery()を使います。

mod_dbd

さて、これまで紹介したAPIは非常にベーシックなものです。Apache HTTP Serverのモジュールで利用する場合は、データベースへの接続を効率良く管理する必要があります。そのためにはmod_dbdというモジュールを組みこむことで適用される独自のAPIが利用できます。

どのようなAPIが提供されるのかについてはmod_dbdを参照してください。実例としては、mod_authn_dbdのソースコードが参考になります。