[SQLite]CでSQLiteのユーザ定義関数を作る その1

2016年10月31日月曜日

sqlite

SQLiteを使ったデータの統計処理なんかをしているとSQL側で処理できてしまうと楽なのになー、と思うケースがあったりする。
そういう時はSQLiteで使えるユーザ定義関数を作ってしまおう。
PHPやPythonで書く手段もあるようだけど、SQLite自体の仕組みを知るためにもCで書いてみよう。

まずは自分で作った関数ではなく、以下で公開されている数値計算用の拡張ライブラリを組み込んでみよう。

SQLite Contributed Files

これを使うと、三角関数やらがSQLから使えるようになる。

最初はSQLite本体のソースコードを以下からダウンロードする。

SQLite Download Page

現時点での最新版は3150000だったので、sqlite-amalgamation-3150000.zipをダウンロード

※環境はOpenSUSE Linux 13.1
$ unzip sqlite-amalgamation-3150000.zip
$ cd sqlite-amalgamation-3150000
$ ls
shell.c  sqlite3.c  sqlite3.h  sqlite3ext.h

既存のSQLite3を使いたい場合はこのままでもいいけど、バージョンを合わせるためにSQLite本体もソースコードからビルドするのであれば、以下の要領で。

$ gcc shell.c sqlite3.c -DHAVE_READLINE -lpthread -ldl -lreadline -lncurses -Os -o sqlite3
$ # -Osはつけてもつけなくてもいいけど、最適化したい場合はつけておこう。

$ ./sqlite3
SQLite version 3.15.0 2016-10-14 10:20:30
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>

拡張ライブラリからリンクするライブラリモジュールを作る時は以下の要領で作成しよう。

$ gcc -shared -fPIC -lpthread -ldl -Os sqlite3.c -o libsqlite3.so

次に以下からextension-functions.cをダウンロードしよう。
SQLite Contributed Files

$ mkdir sqlite-extension
$ cd sqlite-extension
$ gcc -I../sqlite-amalgamation-3150000gcc -I../sqlite-amalgamation-3150000 -L../sqlite-amalgamation-3150000 -fPIC -lm -shared -Os extension-functions.c -o libsqlitefunctions.so -L../sqlite-amalgamation-3150000 -lsqlite3

-Iオプションの後ろはsqlite3ext.hが存在するパスを指定しよう。
システムに入っているSQLite3のライブラリではなく、先ほど自分でビルドしたライブラリモジュールを参照したい場合はリンクのパスにライブラリモジュールのパスを追加しよう。

-L../sqlite-amalgamation-3150000 -lsqlite3

これで、LD_LIBRARY_PATHでライブラリの存在するパスを指定してsqlite3を実行する。
拡張モジュールのロードはsqliteプロンプトで.load モジュール名。

$ LD_LIBRARY_PATH=./../sqlite-amalgamation-3150000/ ../sqlite-amalgamation-3150000/sqlite3
SQLite version 3.15.0 2016-10-14 10:20:30
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> select sin(3.14);
Error: no such function: sin
sqlite> .load libsqlitefunctions
sqlite> select sin(3.14);
0.00159265291648683
sqlite>