Comment compiler une fonction définie par l'utilisateur dans SQLite
-
08-10-2019 - |
Question
J'ai une fonction par exemple C que je voudrais joindre à une base de données temp.sqlite
(il est d'un livre O'Reilly, donc je sais que cela fonctionne). J'ai lu la section dans le livre et sqlite.org, mais ils tiennent pour acquis que je sais comment et où compiler cette chose avec les paramètres appropriés. Je suis sous Mac (avec XCode) ou Ubuntu.
Je sais assez C pour modifier le code pour faire ce que je veux, mais je ne sais pas quoi faire appeler de ma base de données temp.sqlite
.
Merci pour votre aide! J'ai barattage à ce sujet!
Mise à jour: A quelques heures et je l'ai mis au rebut des choses ensemble assez de pages Web pour créer une abandonnés commande compiler et générer une erreur:
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, le wtavg.c d'ici, qui est directement à partir du site O'Reilly fourni dans mon livre:
/* 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;
}
La solution
doit être compilé La fonction définie par l'utilisateur sous forme de fichier bibliothèque partagée:
gcc -shared -fPIC -o wtavg.so wtavg.c -lsqlite3
Cette bibliothèque partagée peut alors être chargé en utilisant une instruction SQLite:
SELECT load_extension('/path/to/wt_avg.so', 'wtavg_init');
Malheureusement, la version de sqlite3 fourni par Apple ne prend pas en charge le chargement des bibliothèques partagées. Vous pouvez utiliser SQLite de MacPorts à la place. programmes MacPorts reliant contre sqlite devraient également avoir la capacité de l'utilisateur charge des fonctions définies ainsi.
Lorsque vous utilisez SQLite dans un autre programme mais le mécanisme de chargement d'extension peut être désactivé pour des raisons de sécurité. En Python par exemple, vous devez appeler con.enable_load_extension(True)
pour l'activer.