Wie eine benutzerdefinierte Funktion in SQLite kompilieren
-
08-10-2019 - |
Frage
ich ein Beispiel C-Funktion haben, dass ich auf eine Datenbank temp.sqlite
anhängen möchten (es ist von einem O'Reilly-Buch, damit ich weiß, es funktioniert). Ich lese den Abschnitt im Buch und sqlite.org, aber sie übernehmen weg, dass ich weiß, wie und wo diese Sache mit den richtigen Einstellungen zu kompilieren. Ich bin auf beide Mac (mit XCode) oder Ubuntu.
Ich weiß genug C, um den Code zu verändern, zu tun, was ich will, aber ich habe keine Ahnung, was es zu tun ruft aus meiner Datenbank temp.sqlite
.
Vielen Dank für Ihre Hilfe! Ich habe auf diese wurde am laufenden Band!
Update: Noch ein paar Stunden in und ich verschrottet habe zusammen genug Sachen aus aufgegeben Webseiten einen Compiler-Befehl zu erstellen und einen Fehler erzeugen:
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, hier wtavg.c, die direkt aus der O'Reilly-Website in meinem Buch vorgesehen ist:
/* 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;
}
Lösung
Die benutzerdefinierte Funktion sollte als Shared Library-Datei kompiliert werden:
gcc -shared -fPIC -o wtavg.so wtavg.c -lsqlite3
Das gemeinsam genutzte Bibliothek kann dann geladen werden, um eine SQLite-Anweisung:
SELECT load_extension('/path/to/wt_avg.so', 'wtavg_init');
Leider ist die Version von sqlite3 von Apple bereitgestellten nicht Laden gemeinsam genutzten Bibliotheken unterstützen. Sie können stattdessen SQLite von MacPorts verwenden. MacPorts Programme Verknüpfung mit SQLite sollte auch die Möglichkeit, Last auf diese Weise definierte Funktionen Benutzer haben.
Bei der Verwendung von SQLite in einem anderen Programm jedoch der Verlängerung Lademechanismus kann aus Sicherheitsgründen deaktiviert werden. In Python zum Beispiel haben Sie Anruf con.enable_load_extension(True)
es zu aktivieren.