Как скомпилировать пользовательскую функцию в SQLite

У меня есть пример функции 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, который прямо с сайта 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;
}

1 ответ

Решение

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

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) чтобы включить его.

Другие вопросы по тегам