sqlite3にはlog関数がない。
ただ、SQLite3 Contributionsというのがあって、そこにextension-functions.cがある。これを使えればlog/log10だけじゃなくて、
Provide mathematical and string extension functions for SQL queries using the loadable extensions mechanism. Math: acos, asin, atan, atn2, atan2, acosh, asinh, atanh, difference, degrees, radians, cos, sin, tan, cot, cosh, sinh, tanh, coth, exp, log, log10, power, sign, sqrt, square, ceil, floor, pi. String: replicate, charindex, leftstr, rightstr, ltrim, rtrim, trim, replace, reverse, proper, padl, padr, padc, strfilter. Aggregate: stdev, variance, mode, median, lower_quartile, upper_quartile.
とか色々使えるようになるらしいんだけど、iphoneSDK上でdylib作ってインクルードする方法がいまさんくらい分からない*1ので、あきらめて、
Distance function for sqlite | This Much I KnowのDaveさんがやっている方法で行く。
とりあえず、てきとうなC言語のヘッダファイルとソースファイルに、目的の関数を作る。
logとlog10が必要なだけなので、ヘッダファイルは以下の通り
// sqlite3_extension_functions.h #ifndef SQLITE3_EXTENSION_FUNCTIONS #define SQLITE3_EXTENSION_FUNCTIONS void sqlite3_extension_log(sqlite3_context *context, int argc, sqlite3_value **argv); void sqlite3_extension_log10(sqlite3_context *context, int argc, sqlite3_value **argv); #endif
実装は引数のチェック後に、標準関数を呼び出しているだけ。
// sqlite3_extension_functions.c #include "sqlite3.h" #include "sqlite3_extension_functions.h" #include "math.h" #include "assert.h" void sqlite3_extension_log(sqlite3_context *context, int argc, sqlite3_value **argv) { assert(argc == 1); if (sqlite3_value_type(argv[0]) == SQLITE_NULL){ sqlite3_result_null(context); return; } double value = sqlite3_value_double(argv[0]); sqlite3_result_double(context, log(value)); } void sqlite3_extension_log10(sqlite3_context *context, int argc, sqlite3_value **argv) { assert(argc == 1); if (sqlite3_value_type(argv[0]) == SQLITE_NULL){ sqlite3_result_null(context); return; } double value = sqlite3_value_double(argv[0]); sqlite3_result_double(context, log10(value)); }
で、sqlite3_openの直後に、sqlite3_create_functionを呼び出して関数を登録する。
int err = sqlite3_open([databasePath fileSystemRepresentation], &db ); if(err != SQLITE_OK) { NSLog(@"error opening!: %d", err); return NO; } //functionの読み込み sqlite3_create_function(db, "log", 1, SQLITE_UTF8, NULL, &sqlite3_extension_log, NULL, NULL); sqlite3_create_function(db, "log10", 1, SQLITE_UTF8, NULL, &sqlite3_extension_log10, NULL, NULL);
第2引数が、SQL内での関数名。第3引数が引数の数。
あとは特に気にしなくていいのでは。
で、
SELECT log(1), log10(1)
とかできる。
まぁ、できればextension-functions.c使いたいけど、あまりがんばるところじゃないので保留。技術力が足りない…orz