mod_dbdでデータベース操作

Apacheモジュールの mod_dbd を試してみます。

mod_dbd はデータベースへのコネクション管理機能を提供するモジュール。
内部で apr_dbd を用いてコネクションプール機能を提供するラッパーモジュールとなっていて、
データベースへの各問い合わせは apr_dbd のAPIを利用します。
Apache Portable Runtime: DBD routines

今回は以下のようなテーブル(dbd_test.user)を対象に dbdtest_module を作ります。
(環境: Apache/2.2.17, APR 1.3.12, APR-Util 1.3.9)

* user *
| id | name | age |
| 1 | foo | 10 |
| 2 | bar | 20 |

* テンプレート作成

$ apxs -g -n dbdtest
Creating [DIR]  dbdtest
Creating [FILE] dbdtest/Makefile
Creating [FILE] dbdtest/modules.mk
Creating [FILE] dbdtest/mod_dbdtest.c
Creating [FILE] dbdtest/.deps
$ cd dbdtest


* mod_dbdtest.c を編集
[cpp]
#include “httpd.h”
#include “http_config.h”
#include “http_protocol.h”
#include “ap_config.h”

#include “apr_dbd.h”
#include “mod_dbd.h”
#include “apr_string.h”

/* The sample content handler */
static int dbdtest_handler(request_rec *r) {
if(strcmp(r->handler, “dbdtest”)) {
return DECLINED;
}
r->content_type = “text/html”;

if(!r->header_only)
ap_rputs(“The sample page from mod_dbdtest.c
“, r);

apr_dbd_results_t* res = NULL;
apr_dbd_row_t* row = NULL;
apr_dbd_prepare_t* stmt = NULL;
ap_dbd_t* dbd = NULL;
int errno;
const char* query = “SELECT * FROM user”;

// データベースへのコネクション確立
if((dbd = ap_dbd_acquire(r)) == NULL) {
ap_rputs(“db handle acquire failed.”, r);
return HTTP_INTERNAL_SERVER_ERROR;
}

// DBドライバ名を取得
ap_rprintf(r, “DBD driver name is %s
“, apr_dbd_name(dbd->driver));

// ステートメントの準備
errno = apr_dbd_prepare(dbd->driver, r->pool, dbd->handle, query, NULL, &stmt);
if(errno != 0) {
ap_rprintf(r, “Error %d %s”, errno, apr_dbd_error(dbd->driver, dbd->handle, errno));
return OK;
}

// 参照系のSQLを発行, 更新系の場合は apr_dbd_pquery を利用する
errno = apr_dbd_pselect(dbd->driver, r->pool, dbd->handle, &res, stmt, 0, 0, NULL);
if(errno != 0) {
ap_rprintf(r, “Error %d %s”, errno, apr_dbd_error(dbd->driver, dbd->handle, errno));
return OK;
}

// 1レコードを取得
while(apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1) != -1) {
// データの取得、添え字の0は最初のカラムを指す
char* id = apr_dbd_get_entry(dbd->driver, row, 0);
char* name = apr_dbd_get_entry(dbd->driver, row, 1);
char* age = apr_dbd_get_entry(dbd->driver, row, 2);
ap_rprintf(r, “id: %s, name: %s, age: %s
“, id, name, age);
}
return OK;
}

static void dbdtest_register_hooks(apr_pool_t *p) {
ap_hook_handler(dbdtest_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA dbdtest_module = {
STANDARD20_MODULE_STUFF,
NULL, /* create per-dir config structures */
NULL, /* merge per-dir config structures */
NULL, /* create per-server config structures */
NULL, /* merge per-server config structures */
NULL, /* table of config file commands */
dbdtest_register_hooks /* register hooks */
};
[/cpp]
* mod_dbdtest.conf を作成

LoadModule dbdtest_module modules/mod_dbdtest.so
<Location "/dbdtest">
  SetHandler dbdtest
</Location>

DBDriver     mysql
DBDParams    "host=localhost port=3306 user=ユーザ名 pass=パスワード dbname=dbd_test"
DBDPersist   On
DBDKeep       5
DBDMax       10
DBDMin        3
DBDExptime  600

* インストール

$ sudo cp mod_dbdtest.conf  (設定ファイルのインストールディレクトリ)
$ make
$ sudo make install
$ sudo apachectl configtest
$ sudo apachectl restart

* 出力結果 (/dbdtest にアクセス)

The sample page from mod_dbdtest.c
DBD driver name is mysql
id: 1, name: foo, age: 10
id: 2, name: bar, age: 20

モジュール作成の手順としては、
1. ap_dbd_acquire 関数を用いてコネクションハンドラを取得
 (ap_dbd_t 構造体の中の apr_dbd_t がコネクションハンドラ)
2. apr_dbd の各APIを用いてデータベースを操作
 型名が ap_dbd だったり、apr_dbd だったり紛らわしいので注意。。
 r が付いていないのが mod_dbd が提供するAPIです。

* 問題点(わからない所)
通常のSQL文を発行する場合は問題ありませんでしたが、ストアドプロシージャをCALLすると、
“PROCEDURE proc_name can’t return a result set inn the given context.”
というエラー(1312)が発生しました。。
確か、libmysqlclientを使ってプロシージャコールをするときも、
オプションを付けてmysql_real_connect()しないとダメだった気がします。
mod_dbdの場合はどうすればいいんだろう。。要調査。

あと、Apacheモジュールについてはwikiの方にもメモを残すことにしました。
Apache – Tech Note

* 参考
漢(オトコ)のコンピュータ道: mod_dbd入門編

あわせて読む:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です