SQLiteを使ってみる
目標は、普通にDBを使える。拡張モジュールを作れるようになる。 そのために拡張モジュールロード、ユーザーSQL関数の登録のコードを少し追う。
使い方の資料
- C-language Interface Specification for SQLite
- SQLite In 3 Minutes Or Less
- An Introduction To The SQLite C/C++ Interface
これらを読んで下のようなサンプルを書いて動く事を確認する。
C Interface sample
|
|
|
|
拡張モジュールでできる事
Run-Time Loadable Extensionsを読んでサンプルを真似して拡張モジュールを作成できる。 拡張モジュールで実現できる事は主に4つ。
拡張モジュールのロード
Cから行う場合、拡張モジュールはsqlite3_load_extension()
で読み込む。
(事前にsqlite3_enable_load_extension
を使いloadを許可する必要がある。SQLiteシェルは事前に実行している。)
コマンドとして.load
コマンド、SQL関数としてload_extension()
関数も提供されている。
共有ライブラリのバイナリの中で次のどちらかの関数を含めると機能する。
sqlite3_extension_init
sqlite3_(file名 - lib)_init
また、モジュールの内容を静的リンクしたSQLite シェルを作りたい場合、 上記エントリポイントをsqlite3_auto_extension に渡しておくと機能するように挟み込める。
拡張モジュール・サンプル
簡単なモジュールを作ってみた。 稼働させると下のように引数を無視して12345を返す。
|
|
ロード実装
sqlite3_load_extension()
内部でsqlite3LoadExtension()
を呼んでいてこれがsqlite3OsDlOpen()
を呼び拡張モジュールファイルをオープンする。
sqlite3OsDlOpen()
はOSなどを隠蔽するだけでUNIXの場合unixDlOpen
が実体となりdlopen()
により呼び出している。
sqlite3LoadExtension()
の返値は動的ライブラリのハンドルでhandle
に格納される。
そして初期化処理としてsqlite3OsDlSym
の呼び出しに使われる。
UNIX系では内部でdlsymにより初期化用関数のアドレスを取得している。
初期化関数の探索sqlite3OsDlSym
は
関数内部でsqlite3_extension_init
,sqlite3_(file名 - lib)_init
の順序で試みており
dlsymで得られたアドレスを関数ポインタへキャストしてxInit
に格納し実行している。
そのため拡張モジュール開発者は上記の関数を提供する必要がある。
ユーザー関数定義
dbに関数定義を行うには下の関数を使えばよい。eTextRepにはエンコード文字種別を登録する。 通常の関数はxFuncのみ、集約関数はxStep, xFinalのみを用いる。それぞれ使わない引数にはNULLを入れる。
|
|
SQLユーザー関数で使えるSQL用APIには以下がある。
sqlite3_create_functionの挙動について
sqlite3_create_function
はsqlite3_create_function_v2
をラップしている。
内部ではsqlite3CreateFunc
を経由してsqlite3FindFunction
が呼び出されている。
これが呼び出されこれが登録処理の中核になっている。
名前としてはsqlite3FindFunction
とFindになっているが、
末尾引数に 0or1を与えられる様になっており存在しない場合に関数の登録先を確保する事も出来る。
そして実際に作る際は、事前に重複するインタフェースや名前を持つ関数が無い事を確認した後、再度Findで格納場所を確保している。
またビルトイン関数と同様FuncDef
構造体として保存される。