2012年11月20日火曜日

SQLiteを使ってみる 第2回

接続したDBにクエリを投げて、以下のような簡単なテーブルを作ってみよう。

日付品目価格

以下のサンプルではsqlite3_exec()を使わず、sqlite3_prepare_v2(), sqlite3_step(), sqlite3_finalize()を使ってクエリを投げている。

// vim: set fileencoding=utf-8:
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>
#define DEFAULT_FILENAME "test2.sqlite3"
int main(int argc, char **argv) {
    sqlite3 *db = NULL;
    int rc;
    char *filename = DEFAULT_FILENAME;
    // open
    if (argc >= 2) filename = argv[1];
    rc = sqlite3_open(filename, &db);
    if (rc == SQLITE_OK)
        printf("sqlite3_open() : OK, db = %p\n", db);
    else
        printf("sqlite3_open() : NG(%d), db = %p\n", rc, db);
    // create table
    const char *query = "create table 家計簿(日付 text, 品目 text, 価格 int);";
//  query = "creat table 家計簿(日付 text, 品目 text, 価格 int);";
    sqlite3_stmt *stmt = (sqlite3_stmt *) 0xdeadbeaf;
    rc = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL);
    if (rc == SQLITE_OK)
        printf("sqlite3_prepare_v2() : OK, stmt = %p\n", stmt);
    else
        printf("sqlite3_prepare_v2() : NG(%d), stmt = %p\n", rc, stmt);
    if (stmt != NULL) {
        rc = sqlite3_step(stmt);
        if (rc == SQLITE_DONE)
            printf("sqlite3_step() : DONE\n");
        else
            printf("sqlite3_step() : NG(%d)\n", rc);
    }
    rc = sqlite3_finalize(stmt);
    if (rc == SQLITE_OK)
        printf("sqlite3_finalize() : OK, stmt = %p\n", stmt);
    else
        printf("sqlite3_finalize() : NG(%d), stmt = %p\n", rc, stmt);
    // close
    rc = sqlite3_close(db);
    if (rc == SQLITE_OK)
        printf("sqlite3_close() : OK, db = %p\n", db);
    else
        printf("sqlite3_close() : NG(%d), db = %p\n", rc, db);
    return 0;
}

sqlite3_prepare_v2()は、UTF-8の文字列で表現されたクエリから内部形式であるsqlite3_stmt型のオブジェクトを生成するAPI。生成されたオブジェクトの場所は、第4引数で参照渡しするポインタ変数に返してもらう。sqlite3_open()とは異なり、失敗したら何もリソースは確保せず、NULLを返す。

sqlite3_prepare_v2()が生成したsqlite3_stmt型のオブジェクトを実行するのがsqlite3_step()。今回はテーブルを作成しているだけなので、クエリの実行結果としてテーブルが返ってきたりはしない。

使い終わったsqlite3_stmt型のオブジェクトは、sqlite3_finalize()で解放する。引数にNULLを渡しても実害はないようだ。

コメントアウトしているクエリは、わざとタイプミスをしたもの。これを実行するとsqlite3_prepare_v2()がエラーを返す。また、コンパイルした実行バイナリを2度3度実行すると、2回目以降はsqlite3_prepare_v2()がエラーを吐く。既存のテーブルと同じ名前のテーブルを作成しようとするので、失敗すること自体は想定していたが、sqlite3_step()でこけるものだと思っていた。sqlite3_open()かsqlite3_prepare_v2()で、DBに含まれているテーブル名くらいは見ているのかな?

0 件のコメント:

コメントを投稿