SQLiteでユーザー定義関数をコンパイルする方法
-
08-10-2019 - |
質問
データベースに添付したいC関数の例があります temp.sqlite
(それはオライリーの本からのものなので、私はそれが機能することを知っています)。私は本とsqlite.orgのセクションを読みましたが、彼らは適切な設定でこのことをどのように、どこでコンパイルするかを知っていると思います。私はMac(Xcodeを使用)またはUbuntuにいます。
私は自分がやりたいことをするためにコードを変更するのに十分なcを知っていますが、データベースから何をすべきかわかりません temp.sqlite
.
ご協力いただきありがとうございます!私はこれをかき回してきました!
更新:さらに数時間で、私は放棄されたWebページから十分なものをまとめてコンパイルコマンドを作成し、エラーを生成しました。
richard$ gcc -o wtavg wtavg.c -Wall -W -O2 -L/usr/local/lib -lsqlite3
wtavg.c: In function ‘wtavg_init’:
wtavg.c:63: warning: unused parameter ‘error’
Undefined symbols:
"_main", referenced from:
start in crt1.10.6.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
fwiw、こちらがwtavg.cです。これは、私の本で提供されているO'Reillyサイトから直接あります。
/* wtavg.c */
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1;
#include <stdlib.h>
typedef struct wt_avg_state_s {
double total_data; /* sum of (data * weight) values */
double total_wt; /* sum of weight values */
} wt_avg_state;
static void wt_avg_step( sqlite3_context *ctx, int num_values, sqlite3_value **values )
{
double row_wt = 1.0;
int type;
wt_avg_state *st = (wt_avg_state*)sqlite3_aggregate_context( ctx,
sizeof( wt_avg_state ) );
if ( st == NULL ) {
sqlite3_result_error_nomem( ctx );
return;
}
/* Extract weight, if we have a weight and it looks like a number */
if ( num_values == 2 ) {
type = sqlite3_value_numeric_type( values[1] );
if ( ( type == SQLITE_FLOAT )||( type == SQLITE_INTEGER ) ) {
row_wt = sqlite3_value_double( values[1] );
}
}
/* Extract data, if we were given something that looks like a number. */
type = sqlite3_value_numeric_type( values[0] );
if ( ( type == SQLITE_FLOAT )||( type == SQLITE_INTEGER ) ) {
st->total_data += row_wt * sqlite3_value_double( values[0] );
st->total_wt += row_wt;
}
}
static void wt_avg_final( sqlite3_context *ctx )
{
double result = 0.0;
wt_avg_state *st = (wt_avg_state*)sqlite3_aggregate_context( ctx,
sizeof( wt_avg_state ) );
if ( st == NULL ) {
sqlite3_result_error_nomem( ctx );
return;
}
if ( st->total_wt != 0.0 ) {
result = st->total_data / st->total_wt;
}
sqlite3_result_double( ctx, result );
}
int wtavg_init( sqlite3 *db, char **error, const sqlite3_api_routines *api )
{
SQLITE_EXTENSION_INIT2(api);
sqlite3_create_function( db, "wtavg", 1, SQLITE_UTF8,
NULL, NULL, wt_avg_step, wt_avg_final );
sqlite3_create_function( db, "wtavg", 2, SQLITE_UTF8,
NULL, NULL, wt_avg_step, wt_avg_final );
return SQLITE_OK;
}
解決
ユーザー定義の関数は、共有ライブラリファイルとしてコンパイルする必要があります。
gcc -shared -fPIC -o wtavg.so wtavg.c -lsqlite3
その共有ライブラリは、sqliteステートメントを使用してロードできます。
SELECT load_extension('/path/to/wt_avg.so', 'wtavg_init');
残念ながら、Appleが提供するSQLite3のバージョンは、共有ライブラリの読み込みをサポートしていません。代わりにMacPortsのSQLiteを使用できます。 SQLiteとリンクするMacPortsプログラムには、この方法でユーザー定義の機能をロードする機能も備えている必要があります。
ただし、別のプログラム内でSQLiteを使用する場合、セキュリティ上の理由により拡張ロードメカニズムが無効になる場合があります。たとえば、Pythonでは、電話する必要があります con.enable_load_extension(True)
それを有効にするため。