SQLiteCppの使い方

メモ

https://spiralsense.jp/blog/2016/09/06/sqlite3-c%e3%83%a9%e3%83%83%e3%83%91%e3%83%bc%e3%83%a9%e3%82%a4%e3%83%96%e3%83%a9%e3%83%aa%e3%80%8csqlitecpp%e3%80%8d%e3%81%ae%e4%bd%bf%e3%81%84%e6%96%b9/spiralsense.jp

元記事消えちゃったので、失礼して復元

SQLiteC++ by SRombauts

非常にシンプルに作られており、とても使い易いライブラリです。

cmakeでビルドする方法が記載されていますが、xcodeではもっと簡単にプロジェクトに組み込めます。

SQLiteCppフォルダをプロジェクトに配置し
SQLiteCpp/include をHeader Serch Pathsに追加して
SQLiteCpp/src/*.cpp、SQLiteCpp/sqlite3.cファイルすべてをCompile Sourcesに追加するだけです。

SQLiteCppの使い方

インスタンスの作り方

#include <SQLiteCpp/SQLiteCpp.h>

int main() {
try {
  SQLite::Database    db("filename");
}
catch (std::exception& e) {
        std::cout << "exception: " << e.what() << std::endl;
}
  return 0;
}

コンストラクタやクエリは例外を投げるのでtry-catchした方がいいです。
コンストラクタは第4引数まで持ちます。

第一引数:ファイル名
第二引数:オープンタイプ

OPEN_READONLY : 読み込み専用
OPEN_READWRITE : 読み書き
OPEN_CREATE : なかったら作る
OPEN_URI : URIも許可する

複数のタイプを組み合わせることができます。(例:SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE)
デフォルト値: OPEN_READONLY

第三引数:データベースがロックされている時のタイムアウト時間[ms]
デフォルト値:0

第四引数: VFSの設定
独自のファイルシステムを指定する際に使う。
デフォルト値:空文字列

成功したかどうかさえわかれば良いタイプのクエリを送る(例: CREATE TABLE)

int nb = db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");

返り値:SQL文で変更された行の数

返り値でSQLITE_OKはかえってきません。
内部でSQLITE_OKかどうかをチェックし、例外を投げる機構が作られてるので、OKチェックをしたい場合はtry-catchしてください。

トランザクションの作成

明示的にトランザクションを使う場合はTransactionクラスを使います。

SQLite::Transaction transaction(db);
        
// dbに関する操作
 
transaction.commit();

もしcommitせずにtransactionインスタンスが破棄された場合、デストラクタでロールバックが行われます。

データを取ってくるクエリ

Statementクラスを使います。

SQLite::Statement   query(db, "SELECT * FROM test WHERE id >= ?");
query.bind(1, 0);
while (query.executeStep()){
   int         id     = query.getColumn(0);
   std::string text   = query.getColumn(1);
   std::cout << "row: " << id << ", " << text << std::endl;
}

エラーをとりたい場合は同様にtry-catchします。

バインドはプレースホルダ「?」を使って行います。
プレースホルダインデックスは1から始まります。注意してください(本家sqlite3は0から)

getColumn関数は対応するインデックスのデータを取得しますが、返り値がColumnというデータラッパクラスです。
プリミティブ型になら何でもキャスト出来る型なので、インデックス等をよく確認するか、isIntegerメソッド等を利用するとデバッグに便利かもしれません。
非explicitキャスト演算子がオーバーロードされているため、以下の3文は等価です。

id      = query.getColumn(0);
id      = static_cast<int>(query.getColumn(0));
id      = (int)query.getColumn(0);

1行目が暗黙キャスト、2行目がC++風キャスト、3行目がC風キャスト。
すべて内部でgetIntメソッドを呼びます。
他の型も同様です。

また、bindは内部でprepareしてくれます。
内部で扱われてるsqlite_stmtラッパクラスのコンストラクタとデストラクタが、prepare-rest-finalizeをやってくれてるからです。