SqLite3を活用する

せっかくブログを作ったので、何か書かないと(汗

SqLite という、オープンソースのデータベースソフトがあります。
http://www.sqlite.org/

ファイルをデータベースとして扱えるので割と手軽に利用できるのが特徴です。

しかし、ここではその使い方ではなくて、SqLiteの中に入っている部品を利用してしまおう
ということを書いてみます。

Sqlite3.2.5のソースパッケージに入っているソースファイル一覧(ヘッダ除く)
alter.c experimental.c os_test.c shell.c update.c
analyze.c expr.c os_unix.c table.c utf.c
attach.c func.c os_win.c tclsqlite.c util.c
auth.c hash.c pager.c test1.c vacuum.c
btree.c insert.c parse.c test2.c vdbe.c
build.c legacy.c pragma.c test3.c vdbeapi.c
callback.c lempar.c prepare.c test4.c vdbeaux.c
complete.c main.c printf.c test5.c vdbefifo.c
date.c md5.c random.c tokenize.c vdbemem.c
delete.c opcodes.c select.c trigger.c where.c

この中でまず目にとまったのが・・・ hash.c

C#Java で使うことができる Hashtable と同様の機能を持っているようです。
全てC言語(C++ではなくて)で書かれてはいますが、オブジェクト指向的な作り方を
してあるようなので、簡単なラッパーを作るだけで使いやすくなるかと思います。
ただし、関数の宣言が全て sqliteInt.h に入っていますので、その中から hash に
関係する物だけを抽出して hash.h などとする必要があります。
C++ の標準ライブラリにハッシュテーブルが加わるまでのつなぎとして使えるかも?


次に気になったのが・・・ printf.c

printf 系は C 言語でおなじみの関数ですが、出力先を標準出力やファイルではなく、メモリに
したい場合(sprintf)に、標準関数ではちょっと不都合があります。

/* == sprintf の使用例 == */
char *s;
...
char buffer[100];
sprintf(buffer, "%s", s);

/* ====== ここまで ====== */
これは buffer に s の中に入っている文字列を入れる処理をしますが、もし s の中に
100文字以上の文字が入っていたら、メモリ書き込み違反が起きてしまいます。これを
防ぐためには、2番目のフォーマット引数と3番目以降の引数から、文字数を計算して
それを全て書き込めるだけの領域を確保する、などの処理が必要となります。
printf.c 中の関数に、まさにそれをやっているものがあるみたいです。

sqlite3_mprintf
sqlite3_vmprintf

引数の渡し方は printf と同じ。関数を実行すると、
malloc により格納したい文字列分の領域を確保
・確保した領域に、与えられた引数にしたがって文字列を書き込む
・そのアドレスを返す
という処理をするようです。
(なので、作成した文字列が不要になったら free で解放してあげる必要がありますね。)
これなら、使う側が文字列の長さを気にしなくて済みますから気楽に使えると思います。
まあ、boost::format で同様のことができるという説もありますが・・・