Skip to main content

SQLite使用説明(VC++言語)(3)

4.パラメータ設定

SQLにパラメータを渡すには、二つの方法があります。

1. SQL文を組み立てて、値を埋める

CString sql;
sql.Format( _T("SELECT name FROM Names WHERE name = '%s'"), _T("Tom") );

CStringを使用するためUnicodeに対応するsqlite3_prepare16を使用します。

int rc = sqlite3_prepare16( db, sql, -1, &stmt );

この方法でSQL文を組立てる場合、SQLインジェクションという不正利用がおこる可能性がありますので、以下の方法2を推奨します。

2. SQLパラメータを使用する

上記方法1の’%s’のところを?で書き込みます。

int rc = sqlite3_prepare( db, "select name from names where name = ?", -1, &stmt );

そしてsqlite3_bindを使用して値を設定します。
値の型によって、以下の設定関数を使うことができます。

int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); 
int sqlite3_bind_double(sqlite3_stmt*, int, double); 
int sqlite3_bind_int(sqlite3_stmt*, int, int);
int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
int sqlite3_bind_null(sqlite3_stmt*, int);
int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);

使用例:

sqlite3_bind_text16( stmt, 1, _T("UNVELLソフトウェア"), SQLITE_STATIC );

5.その他

5.1. ONE STEPでデータベースを操作する

上記のように、データを取得する場合は、sqlite3_preparesqlite3_stepsqlite3_columnの三つの関数を使用する必要があります。

sqlite3_exec関数を使用する場合は、上記3 STEPsの操作を1 STEPに削減できます。
sqlite3_execの定義は以下の通りです。

int sqlite3_exec(
    sqlite3*,                                    /* データベースオブジェクト */
    const char *sql,                             /* 実行するSQL */
    int (*callback)(void*,int,char**,char**),    /* コールバック関数 */
    void *,                                      /* コールバックに渡す引数 */
    char **errmsg                                /* エラー情報 */
);

渡したSQLが実行されレコードが取得された後に、コールバック関数が呼び出されます。
その時に渡された一行のデータを処理します。

例:コールバック関数を定義します。

static int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
    int i;
    for (i=0; i < argc; i++) {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");
    return 0;
}

そしてSQLを実行します。

int rc = sqlite3_open( "test.db", &db );
char* zErrMsg = NULL; /* エラーメッセージへ指向ポインター */ 
rc = sqlite3_exec(db, "SELECT * FROM Names", callback, 0, &zErrMsg);

/* エラーメッセージが返された場合はぜひ解放しましょう。 */
if( zErrMsg != NULL ) sqlite3_free( zErrMsg );

sqlite3_close(db);

5.2. 高速化&効率化

SQL文を変えずに、複数のデータを挿入したい場合は、 コンパイラステートメントを破棄せず、
一回コンパイラして 複数回使用したほうが高速化、効率化できます。

以下のパターン1で示した使い方ではなく、パターン2にしましょう。

パターン1: 誤×

int rc = sqlite3_open( "test.db", &db );
sqlite3_stmt* stmt;
const TCHAR* szNames[] = { L"Bright", L"Owen", L"Alfred" };
for (int i = 0; i < _countof(szNames); i++) {
    sqlite3_prepare( db, "insert into Names ( name ) values (?)", 
        -1, &stmt, NULL );
    sqlite3_bind_text16( stmt, 1, szNames[i], -1, SQLITE_STATIC );
    sqlite3_step( stmt );
    sqlite3_finalize( stmt );
}
sqlite3_close( db );

パターン2: 正○

int rc = sqlite3_open( "test.db", &db );
sqlite3_stmt* stmt;
const TCHAR* szNames[] = { L"Bright", L"Owen", L"Alfred" };
rc = sqlite3_prepare( db, "INSERT INTO Names ( name ) VALUES ( ? )",
   -1, &stmt, NULL );
for (int i = 0; i < _countof(szNames); i++) {
    sqlite3_bind_text16( stmt, 1, szNames[i], -1, SQLITE_STATIC );
    sqlite3_step( stmt );
    sqlite3_reset( stmt );
}
sqlite3_finalize( stmt );
sqlite3_close( db );

6.エラー処理

6.1. エラー検出

ほとんど全てのsqlite3関数はintタイプの戻りコードを返すので、それによって
エラーが発生したかどうかを判断できます。

int rc = sqlite3_...( ... ) 
if (rc != SQLITE_OK)
{
    /* 最後のエラーメッセージを取得する */
    AfxMessageBox( (LPCTSTR) sqlite3_errmsg16( db ) );         
}

6.2. エラー処理

一般的にsqlite3_*関数のint型の戻り値を判断すると成功かエラーか判断できます。

例:

int rc = sqlite3_open("test.db", db);
int rc = sqlite3_step(stmt);           /* SQL実行する */

sqlite3_stepの場合、SQL操作によって以下の二つの戻り値が返されます。

INSERT,UPDATE,DELETE操作の場合 SQLITE_DONE
SELECT操作の場合 SQLITE_ROW

sqlite3_*関数の戻り値以外には、以下のエラー処理に関係する関数が
用意されています。

int sqlite3_errcode(sqlite3 *db); 最後のエラーコードを取得する
int sqlite3_extended_errcode(sqlite3 *db); 最後の拡張エラーコードを取得する。
const char *sqlite3_errmsg(sqlite3*); 最後のエラーメッセージを取得する
const void *sqlite3_errmsg16(sqlite3*); 最後のUnicodeエラーメッセージを取得する(推奨)

特に、日本語が含まれている場合があるので、sqlite3_errmsg16の使用をお勧めします。

返却コード一覧表

成功系

定数 説明
SQLITE_OK 0 成功

失敗系

定数 説明
SQLITE_ERROR 1 SQLエラー
SQLITE_INTERNAL 2 外部エラー
SQLITE_PERM 3 権限で取り扱えない
SQLITE_ABORT 4 コールバックが中断を要求する
SQLITE_BUSY 5 データベースファイルはロックされている
SQLITE_LOCKED 6 テーブルがロックされている
SQLITE_NOMEM 7 メモリ不足(malloc関数失敗)
SQLITE_READONLY 8 読込専用のデータベースに書き込むエラー
SQLITE_INTERRUPT 9 操作が中断された(sqlite3_interrupt()に)
SQLITE_IOERR 10 ディスクI/O失敗
SQLITE_CORRUPT 11 The database disk image is malformed
SQLITE_NOTFOUND 12 テーブルかレコードが存在しない(使用していない)
SQLITE_FULL 13 データベースがFull
SQLITE_CANTOPEN 14 データベースファイルを開けない
SQLITE_PROTOCOL 15 データベースロックプロトコール(使用していない)
SQLITE_EMPTY 16 データベースが空
SQLITE_SCHEMA 17 データベースのスキーマが変更された
SQLITE_TOOBIG 18 文字列かBLOBデータが大きすぎる
SQLITE_CONSTRAINT 19 Abort due to constraint violation
SQLITE_MISMATCH 20 データタイプが不適切
SQLITE_MISUSE 21 Library used incorrectly
SQLITE_NOLFS 22 OS機能が支持されていない
SQLITE_AUTH 23 アクセス権限がない
SQLITE_FORMAT 24 Auxiliary database format error
SQLITE_RANGE 25 パラメータの番号が範囲以外
SQLITE_NOTADB 26 指定したファイルはデータベースフォーマットではない
SQLITE_ROW 100 後一行のデータが存在する
SQLITE_DONE 101 操作が正しく行われた

拡張エラーコード一覧

定数
SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))
SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))
SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))
SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8))
SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8))
SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8))
SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8))
SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8))
SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8))
SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8))
SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8))
SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) )

[前のページへ]

Jingwood

北海道の田舎で暮らしているプログラマーです。最近山登りにハマりました。

2 thoughts to “SQLite使用説明(VC++言語)(3)”

Leave a Reply

Your email address will not be published. Required fields are marked *