2016年8月12日金曜日

SQLite3のプログラムの勉強

ちょっとSQLite3を使ったプログラムをWindowsで作るとどうなるのか調べてみたくなりました。ただ私は普段LinuxかMacでプログラムを作ることが圧倒的に多いので、まずは慣れたMac、Xcodeで作ってみます。

1. sqlite3のインストール
brewを使ってインストールしています。コマンドラインでも使えますし、ヘッダ、ライブラリも一緒にインストールしてくれます。

2. プログラムの作成
とりあえず、以下の様なプログラムを作ってみました。
//
// main.cpp
// SQLiteTest
//
// Created by hiro on 2016/08/11.
// Copyright © 2016年 hiro.maeda. All rights reserved.
//
#include <stdlib.h>
#include <iostream>
#include <sqlite3.h>
int main(int argc, const char * argv[]) {
// dbファイルを指定した場所に作るための確認用コード
std::string home = getenv("HOME");
std::cout << "$HOME = " << home << std::endl;
home += "/ProgWork/SQLite";
std::cout << "$HOME = " << home << std::endl;
// ここから本体
std::string dbfile = home + "/test.db"; // DBファイル
sqlite3* db = NULL;
// dbのオープン
int err = sqlite3_open(dbfile.c_str(), &db);
if (err != SQLITE_OK)
{
// dbファイルオープン失敗
std::cout << "OPEN ERROR " << err << std::endl;
exit(-1);
}
std::cout << "OPEN SUCCESS!" << std::endl;
// SQLの実行(insert)
char* errCode = NULL;
err = sqlite3_exec(db, "insert into tbl_test(id, name) values('123', 'hoge');", NULL, NULL, &errCode);
if (err != SQLITE_OK)
{
// SQL実行失敗
std::cout << "INSERT ERROR " << err << ":" << errCode << std::endl;
err = sqlite3_close(db);
exit(-1);
}
// SQLの実行(select)
sqlite3_stmt* pStmt = NULL;
// データの抽出、ステートメントの用意
err = sqlite3_prepare_v2(db, "select * FROM tbl_test where id=123", 64, &pStmt, NULL);
if (err != SQLITE_OK)
{
// SQL実行失敗
std::cout << "SELECT ERROR " << err << std::endl;
err = sqlite3_close(db);
exit(-1);
}
else
{
// データの抽出
while (SQLITE_ROW == (err = sqlite3_step(pStmt)))
{
int id = sqlite3_column_int(pStmt, 0);
const unsigned char* name = sqlite3_column_text(pStmt, 1);
std::cout << "id: " << id << ", name: " << name << std::endl;
}
if (err != SQLITE_DONE)
{
std::cout << "SELECT DONE ERR" << std::endl;
err = sqlite3_close(db);
exit(-1);
}
}
// ステートメントの解放
sqlite3_finalize(pStmt);
// dbのクローズ
err = sqlite3_close(db);
if (err != SQLITE_OK)
{
// dbファイルクローズ失敗
std::cout << "CLOSE ERROR " << err << std::endl;
exit(-1);
}
std::cout << "CLOSE SUCCESS!" << std::endl;
return 0;
}

とてもシンプルです。実行結果は以下の様になります。

$HOME = /Users/hogehoge
$HOME = /Users/hogehoge/ProgWork/SQLite
OPEN SUCCESS!
id: 123, name: hoge
CLOSE SUCCESS!

createがありませんが、そこはマニュアルで作っています。(プログラムに書いてもいいんですが、毎回実行するためにいちいちdbファイルを削除するのも面倒なので。)

> create table tbl_test(id integer primary key, name text);

最終的にはinsertのところをupdateに変えて、プロセス間の通信代わりに使おうと目論んでいます。

3. 注意点

  • Xcodeの設定でライブラリの追加オプション"-lsqlite"を忘れない様に。
  • 単純にやろうと思うなら、sqlite_open(), sqlite_close(), sqlite_exec()だけで済ますこともできます。ただselect文をsqlite_exec()でやろうとすると、どうしても出力をcallbackで受けないといけなくなります。callback関数を書くのが面倒だったので、非同期クエリで実装しています。(こちらも面倒だがやむを得ません)
  • sqliteはsql文の実行ではデフォルトでオートトランザクションになっています。将来的にプロセス間の通信に使うつもりなら本当は、"bgein","commit"と明確にトランザクションの指定をしてやるべきです。ただそんな複雑な通信は当面する気がなく、一方向だけ(片方がwriteして、他方はreadするだけ)のつもりなので、当面はこれでも問題はありません。
さて、これをwindowsのVisualStudioのc++で実装です。2015ではUWPアプリ(Universal Windows Platform)として、SDKにsqlite3が標準で入っているらしいです。実装もこのままでコンパイルが通りましたが、リンクでどうしてもsqlite関係の関数が「未解決の外部シンボル」と言われてしまいます。(ちゃんとwinsqlite3.libを追加のライブラリに指定しているんですが・・・)ちょいとこの問題の解決には時間がかかっています。


0 件のコメント:

コメントを投稿