Domanda

Ho un esempio di funzione C che vorrei collegare a un database di temp.sqlite (è da un libro di O'Reilly, quindi so che funziona). Ho letto la sezione nel libro e sqlite.org, ma presumo via che io so come e dove compilare questa cosa con le impostazioni corrette. Sono su entrambi i Mac (con XCode) o Ubuntu.

Lo so abbastanza C per alterare il codice per fare quello che voglio, ma non ho idea di cosa fare chiamare dal mio temp.sqlite database.

Grazie per il vostro aiuto! Sono stato a sfornare su questo!

Update: Ancora qualche ore in e ho scartato abbastanza roba insieme da pagine web abbandonate per creare un comando di compilazione e generare un errore:

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, di qui wtavg.c, che è direttamente dal sito di O'Reilly fornita nel mio libro:

/* 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;
}
È stato utile?

Soluzione

La funzione definita dall'utente deve essere compilato come file di libreria condivisa:

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

Questa libreria condivisa può essere caricata utilizzando una dichiarazione SQLite:

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

Purtroppo la versione di sqlite3 fornito da Apple non supporta il caricamento delle librerie condivise. È possibile utilizzare SQLite da MacPorts invece. MacPorts programmi che collegano contro SQLite dovrebbero anche avere la capacità di funzioni definite dall'utente carico in questo modo.

Quando si utilizza SQLite all'interno di un altro programma invece il meccanismo di estensione di carico può essere disattivato per motivi di sicurezza. In Python per esempio si deve chiamare con.enable_load_extension(True) per attivarlo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top