概要
どうも、@daiki1003です!sqlite3を使おうと思い、色々な参考になりそうなブログを回遊しました。
そして、メインとなるメソッドが分かったので公式サイトを見て和訳してみました。
現状(2015/02/27)は3.8.8.3が最新でしょうか。
もし、正しくない表現や誤解を生みそうな表現があれば指摘いただければと思います。
@daiki1003まで。
それではいきましょう。
メモなので読みにくいところはご了承下さい。
sqlite3_open
int sqlite3_open(const char *filename, sqlite3 **ppDb);
int sqlite3_open16(const char *filename, sqlite3 **ppDb);
int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs);
・open, open_v2のfilenameはUTF-8, open16はUTF-16
・v2はflagsとzVfsを余分に取る
flagsには以下のどちらかまたは両方を取る
「SQLITE_OPEN_NOMUTEX, SQLITE_OPEN_FULLMUTEX, SQLITE_OPEN_SHAREDCACHE, SQLITE_OPEN_PRIVATECACHE」
「SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE」
SQLITE_OPEN_READONLY
readonlyでopen
SQLITE_OPEN_READWRITE
readwriteでopen, 書き込みが不可能ならreadonly
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
readwriteでopen,かつもし存在しなければ作成する。sqlite3_openとsqlite3_open16はこのモードで実行される
zVfsはsqlite3_vfsの名前を指定
:memory:を指定すると、オンメモリのDBが作成されdbがcloseされると消える
今後:から始まるものは増える予定
空文字を入れると、プライベートな一時的なdbがディスクに生成され、db接続が切れるとすぐに削除される
sqlite3_close
sqlite3_close(sqlite3*);
sqlite3_close_v2(sqlite3*);
正しくclose出来ればSQLITE_OKを返す、リソースが廃棄される
もしdbが作業中であればSQLITE_BUSYを返す
transaction中のcloseであればロールバックされる
sqlite3_exec
int sqlite3_exec(sqlite3*, const char *sql, int (*callback)(void*,int,char**,char**), void *, char **errmsg);
sqlite3_execはsqlite3_prepare_v2(),sqlite3_step(),sqlite3_finalize()の簡易ラッパーである
UTF-8のセミコロンで区切られたSQLが第二引数に渡され、データベース接続が第一引数に渡される
コールバックである第三引数がNULLでなければSQLによって取り出された行それぞれに対して呼び出される
第四引数はコールバック実行の際に第一引数に渡される
sqlite3_execのコールバックポインタがNULLならコールバックは実行されず結果行は無視される
もしSQLの評価時にエラーが生じた場合、現在のステートメントの実行は中止され、続くステートメントはスキップされる
第五引数がNULLでなければエラーメッセージが書き込まれる
メモリリークを避けるため、エラーメッセージが必要なくなったらsqlite3_free()でエラーメッセージの文字列を実行しなければならない
もし第五引数がNULLでなくエラーが起きなければsqlite3_execはリターンする前に第五引数のポインタをNULLにする
もしsqlite3_exec()のコールバックが0以外の値を返した場合、sqlite3_exec()は直ちにSQLITE_ABORTを返却する
sqlite3_exec()のコールバック関数の第二引数は結果のカラム数である
sqlite3_exec()のコールバック関数の第三引数はそれぞれのカラムにおいてsqlite3_column_text()を実行すれば得られるであろう文字列の配列である
結果がNULLであればNULLポインタが返る
sqlite3_exec()のコールバック関数の第四引数はsqlite3_column_name()によって得られる結果カラムの名前のポインタの配列である
もしsqlite3_exec()の第二引数がNULLポインタ、空文字へのポインタまたは空白文字やコメントのみを含む場合、SQLステートメントは評価されずデータベースに変更はない
※制限
◎アプリケーションはsqlite3_exec()の第一引数は正しく接続されたデータベースである事を保証しなければならない
◎アプリケーションは第一引数に渡されたデータベース接続をsqlite3_exec()を実行している間は閉じてはならない
◎アプリケーションは第二引数に渡されたSQLステートメントをsqlite3_exec()を実行している間は変更してはならない
sqlite3_prepare
int sqlite3_prepare(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
int sqlite3_prepare_v2(sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail);
int sqlite3_prepare16(sqlite3 *db, const void *zSql, int nByte, sqlite3_stmt **ppStmt, const void **pzTail);
int sqlite3_prepare16_v2(sqlite3 *db, const void *zSql, int nByte, sqlite3_stmt **ppStmt, const void **pzTail);
・dbはopenによって得られたdb
・zSqlはコンパイルするsql, UTF8なら上二つ、UTF16なら下二つ
・nByteは-1でまぁ良い
・成功したらSQLITE_OKを返す、失敗ならerror_codeを返す
sqlite3_stmt
(stmtはstatementの略ぽい)
・SQLステートメントの状態を表すインスタンス
・ライフサイクルはこんな感じ
1. sqlite3_prepare_v2()かそれに関するfunctionで生成
2. sqlite3_bind_*()で変数をbind
3. sqlite3_step()でSQLを実行, 1回かそれ以上これを実行する.
4. sqlite3_resetで状態をリセットし、2.に戻る。0回かそれ以上これを実行する.
5. sqlite3_finalize()でこれを廃棄する
sqlite3_step
int sqlite3_step(sqlite3_stmt*);
prepareが実行された後ステートメントを評価するため、1回かそれ以上実行される。
v2を使うか古い方を使うかで細かい動作が違う、v2推奨だが引き続き古い方もサポートは刷る
古い方だと、SQLITE_BUSY,SQLITE_DONE,SQLITE_ROW,SQLITE_ERRORかSQLITE_MISUSEのどれかが返って来る
v2だと結果コードが返って来る
SQLITE_BUSY: dbのjobが実行中のため、lockが獲得出来なかった場合
もし、COMMITやtransaction外であれば再実行可能であるが、COMMITでなく、transaction内なら続ける前にrollbackすべきである
SQLITE_DONE: 正しく実行された
sqlite3_reset()を呼ぶ前に、sqlite3_step()はもう呼んでは駄目.
もし投げたSQLが何らかのデータを返す場合、SQLITE_ROWがその都度返却され、その値にアクセス出来る。
sqlite3_step()は再度実行される
SQLITE_ERROR: ランタイムエラーが起きた場合
sqlite3_step()は呼んでは駄目、更に情報が欲しければsqlite3_errmsg()を呼ぶ。
古い方であればSQLITE_INTERRUPT, SQLITE_SCHEMA, SQLITE_CORRUPTなどがsqlite3_reset()を呼ぶ事により、返却される
v2であればより詳細なエラーコードがsqlite3_step()によってダイレクトに返却される
SQLITE_MISUSE: その名の通り、使い方がミスっている場合
finalizeされたステートメントや、SQLITE_ERRORやSQLITE_DONEを返すようなステートメントの場合など。
ないし二つ以上のスレッドから同一のdbにコネクションを貼ろうとした場合など。
※3.6.23.1以下のバージョンではsqlit3_step()がSQLITE_ROW以外を返した場合次のsqlite3_step()を呼ぶ前に、sqlite3_reset()の呼び出しが必要
やらないとsqlite3_step()からSQLITE_MISUSEが返る
3.6.23.1以降ならsqlite3_step()が勝手に呼ぶから必要ない
sqlite3_reset
int sqlite3_reset(sqlite3_stmt *pStmt);
再実行が出来る最初の状態に戻す為に使う
bindingをリセットするにはsqlite3_clear_bindings()を使う
もし直近のsqlite3_step()がSQLITE_ROWないしSQLITE_DONEを返すかsqlite3_step()が呼ばれていない場合、sqlite3_reset()はSQLITE_OKを返す
もし直近のsqlite3_step()がエラーを返していた場合、sqlite3_reset()は適切なエラーコードを返す
sqlite3_reset()はSのバインディングは変更しない
sqlite3_finalize
int sqlite3_finalize(sqlite3_stmt *pStmt);
ステートメントの削除に使う
もし直近のステートメントの評価時にエラーがないか一度もステートメントが評価されていない場合、sqlite3_finalize()はSQLITE_OKを返す
もし直近のステートメントの評価に失敗していた場合、sqlite3_finalize()はエラーコードを返す
sqlite3_finalize()はステートメントのライフサイクル内であればいかなるポイントでも呼ぶ事が出来る
ステートメントが評価される前、一回以上sqlite3_reset()が呼ばれた後、成功失敗問わずsqlite3_step()が実行された後等である
ぬるぽに対してsqlite3_finalize()は不可能である
リソースのリークを防ぐため全てのステートメントに対してfinalizeは行うべきである
finalizeされた後のステートメントを使用するのはとても危険である
segfaultsとかヒープ破損とかが起こりうる
大量のinsertをする場合は明示的にBEGINとCOMMITを打つ
以上です。
誰かのお役に立てば。Twitterフォローお願いします
「次回以降も記事を読んでみたい!」「この辺分からなかったから質問したい!」
そんな時は、是非Twitter (@daiki1003)やInstagram (@ashdik_flutter)のフォローお願いします♪
Twitterコミュニティ参加お願いします
Twitterコミュニティ「Flutter lovers」を開設しました!参加お待ちしております😁
☕️ Buy me a coffee
また、記事がとても役に立ったと思う人はコーヒーを奢っていただけると非常に嬉しいです!
コメント