sqlite3をc/c++で使う方法についてメモ。
以前ruby で sqlite を使う方法 - ぴょぴょぴょ? - Linuxとかプログラミングの覚え書き -でも書いたように、DBを使うアプリケーションは、通常はrubyなどのスクリプト言語で記述したほうが楽です。
でもc/c++からもデータベースを使えると非常に便利です。
公式なリファレンスマニュアル
http://www.sqlite.org/capi3ref.html 全APIの一覧があります
インストール
debian であれば libsqlite3-dev を入れるだけです.
$ sudo apt-get update $ sudo apt-get install libsqlite3-dev
sqlite3 のAPI
よく使うAPIを列挙していきます
Database への接続
データーベースとして、 hogehoge.db というファイルを開きます。
const char *name="hogehoge.db"; sqlite3 *db=NULL; int r = sqlite3_open(name, &db); if (SQLITE_OK!=r){ // open失敗 }
閉じる場合は
sqlite3_close(db);
SQLの実行
遅くてもいいので、とにかくSQLを実行したい場合は sqlite3_exec() を使うと楽です。
char *err=NULL; sqlite3_exec(db, "create table tbl_test(id integer,name text);", NULL, NULL, &err);
sqlite3_exec(db, "insert into tbl_test (id, name) values('123', 'hoge');", NULL, NULL, &err);
ただしsqlite3_exec() はクエリが完了するまで、呼び出し側スレッドを休眠させます。いわゆるブロッキング関数です。
パフォーマンスを重視する場合はクエリを非同期に実行する方法が有効です。非同期にクエリを実行するには以下のAPIを組み合わせて処理を記述します。
- sqlite3_prepare()を使って stmt を生成
- sqlite3_reset()を使って stmt の内部バッファをクリア
- 必要に応じて sqlite3_bind_??() でクエリを加工
- sqlite3_step() を使って クエリを実行
- sqlite3_finalize() を使って stmt を開放
使用例は以下のようになります。
// stmt を生成する const char *sql = "insert into tbl_test (id, name) values('?', '?');"; sqlite3_stmt *stmt=NULL; sqlite3_prepare(db, sql, strlen(sql), &stmt, NULL); // stmtの内部バッファを一旦クリア sqlite3_reset(stmt); // sqlの?の部分に、値を設定 int id=123; const char *name="hoge"; sqlite3_bind_int(stmt, 0, id); sqlite3_bind_text(stmt, 1, name); // stmtのSQLを実行 int loop=0; while (SQLITE_DONE != sqlite3_step(stmt)){ if (loop++>1000){ // エラー } } // stmt を開放 sqlite3_finalize(stmt);
かなり面倒です。クエリの実行はsqlite3_step() で行われます。返り値は、以下の値をとります。
- SQLITE_ERROR:クエリが何らかの理由によりエラーとなった場合
- SQLITE_ROW: クエリの結果が列として取れる場合
- SQLITE_BUSY: クエリが未完の場合
- SQLITE_DONE: クエリが完了時
sqite3_step() は非同期にクエリを実行するので、上記返り値を使ったDBと同期を取るようなコーディングが必須となります。
SQLの実行結果の取得方法 (select文のつかいかた)
// stmt を生成する const char *sql = "select id, name from tbl_test"; sqlite3_stmt *stmt=NULL; sqlite3_prepare(db, sql, strlen(sql), &stmt, NULL); // stmtの内部バッファを一旦クリア sqlite3_reset(stmt); // stmtのSQLを実行し、結果を一列づつ取得 int r; while (SQLITE_ROW == (r=sqlite3_step(stmt))){ int id = sqlite3_column_int(stmt, 0); const char *name = sqlite3_column_text(stmt, 1); } if (SQLITE_DONE!=r){ // エラー } // stmt を開放 sqlite3_finalize(stmt);
エラー処理
- APIの返り値を毎回確認しましょう (ToT)
トランザクション transaction
専用のAPIは用意されていません。
SQLの begin, commit 文を個別に sqlite3_exec()で発行します。
sqlite3_exec(db, "begin;", NULL, NULL, NULL);
sqlite3_exec(db, "commit;", NULL, NULL, NULL);