PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Crea una copia della funzione C interna di PostgreSQL e caricala come funzione definita dall'utente

Il motivo per cui il client psql chiede se desideri riconnetterti è perché il backend è in segfault, come da commenti.

Sarebbe possibile raccogliere un core dump da un arresto del genere ed esaminarlo con un debugger (ad es. gdb) per scoprire esattamente dove si sta arrestando in modo anomalo. Tuttavia, la mia ipotesi migliore è che si stia arrestando in modo anomalo perché hai preso un file di grandi dimensioni scritto per essere un componente principale di postgresql, lo hai compilato separatamente e hai tentato di caricarlo come modulo di estensione.

Il file numeric.c contiene un numero enorme di funzioni, variabili statiche e strutture dati, di cui stai cercando di duplicarne solo una. Tutte queste funzioni, variabili, ecc. esistono già nel sistema postgresql in esecuzione. Quando compili la tua versione di numeric.c e la carichi, la nuova funzione che stai aggiungendo farà riferimento alle funzioni e alle variabili nella tua libreria invece di usare quelle nel programma postgresql principale. Probabilmente fa riferimento a strutture di dati che non sono state inizializzate correttamente, causandone l'arresto anomalo.

Ti consiglio di iniziare con un file vuoto e di copiare solo la funzione int2_avg_accum da numeric.c (rinominato come hai fatto). Se quella funzione chiama altre funzioni in postgresql o fa riferimento a variabili, utilizzerà le funzioni e le variabili nel binario postgresql principale, che è quello che vuoi. Puoi #includere l'originale numeric.h per ottenere le dichiarazioni di tutte le funzioni esterne.

Esistono altre differenze tra il modo in cui la funzione viene definita come funzione interna e come deve essere definita quando viene caricata come modulo caricato dinamicamente:

  • Dovevi specificare che stai utilizzando la convenzione di chiamata V1 aggiungendo la macro:

    PG_FUNCTION_INFO_V1(int2_avg_accum2);

    Se manca questo causerà anche segfault perché postgresql assumerà le convenzioni di chiamata della versione 0, che non corrispondono alla definizione della funzione!

  • Come hai indicato devi includere PG_MODOULE_MAGIC.

Il file completo, che ha funzionato per me, è:

#include "postgres.h"
#include "fmgr.h"
#include "utils/array.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

typedef struct Int8TransTypeData
{
    int64       count;
    int64       sum;
} Int8TransTypeData;

PG_FUNCTION_INFO_V1(int2_avg_accum2);

Datum
int2_avg_accum2(PG_FUNCTION_ARGS)
{
    ArrayType  *transarray;
    int16       newval = PG_GETARG_INT16(1);
    Int8TransTypeData *transdata;

    /*
     * If we're invoked as an aggregate, we can cheat and modify our first
     * parameter in-place to reduce palloc overhead. Otherwise we need to make
     * a copy of it before scribbling on it.
     */
    if (AggCheckCallContext(fcinfo, NULL))
        transarray = PG_GETARG_ARRAYTYPE_P(0);
    else
        transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);

    if (ARR_HASNULL(transarray) ||
        ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
        elog(ERROR, "expected 2-element int8 array");

    transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
    transdata->count++;
    transdata->sum += newval;

    PG_RETURN_ARRAYTYPE_P(transarray);
}

Compilato con:

gcc -I/usr/pgsql-9.2/include/server -fPIC -c my_avg_accum.c
gcc -shared -o my_avg_accum.so my_avg_accum.o

Stavo usando Postgresql 9.2 su Centos 6. Potrebbe essere necessario regolare i percorsi in base alla configurazione.