Как скомпилировать пользовательскую функцию в SQLite - PullRequest
0 голосов
/ 12 ноября 2010

У меня есть пример функции C, которую я хотел бы прикрепить к базе данных temp.sqlite (она из книги О'Рейли, поэтому я знаю, что она работает). Я прочитал раздел в книге и sqlite.org, но они предполагают, что я знаю, как и где скомпилировать эту вещь с правильными настройками. Я либо на Mac (с XCode), либо на Ubuntu.

Я знаю достаточно C, чтобы изменить код, чтобы делать то, что я хочу, но я понятия не имею, что делать, вызвать его из моей базы данных temp.sqlite.

Спасибо за вашу помощь! Я бился об этом!

Обновление: еще несколько часов, и я собрал достаточно вещей с оставленных веб-страниц, чтобы создать команду компиляции и выдать ошибку:

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, прямо с сайта О'Рейли, представленного в моей книге:

/* 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;
}

1 Ответ

3 голосов
/ 12 ноября 2010

Определяемая пользователем функция должна быть скомпилирована как файл общей библиотеки:

gcc -shared -fPIC -o wtavg.so wtavg.c -lsqlite3

Эта общая библиотека может быть загружена с помощью оператора SQLite:

SELECT load_extension('/path/to/wt_avg.so', 'wtavg_init');

К сожалению, версия sqlite3, предоставляемая Apple, не поддерживает загрузку общих библиотек. Вместо этого вы можете использовать sqlite от MacPorts. Программы MacPorts, ссылающиеся на sqlite, также должны иметь возможность загружать определенные пользователем функции таким образом.

При использовании SQLite внутри другой программы, однако механизм загрузки расширения может быть отключен по соображениям безопасности. Например, в Python вы должны вызвать con.enable_load_extension(True), чтобы включить его.

...