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

Opret kopi af PostgreSQL intern C-funktion og indlæs den som brugerdefineret funktion

Grunden til, at psql-klienten spørger, om du ønsker at oprette forbindelse igen, er, at backend'en er segfaulting ifølge kommentarerne.

Det ville være muligt at indsamle et kernedump fra et sådant nedbrud og undersøge det med en debugger (f.eks. gdb) for at finde ud af præcis, hvor det går ned. Mit bedste gæt er dog, at det går ned, fordi du har taget en stor fil skrevet til at være en kernekomponent i postgresql, kompileret den separat og forsøgt at indlæse den som et udvidelsesmodul.

Filen numeric.c indeholder et stort antal funktioner, statiske variabler og datastrukturer, hvoraf du kun forsøger at duplikere én. Alle disse funktioner, variabler osv. findes allerede i det kørende postgresql-system. Når du kompilerer din version af numeric.c og indlæser den, vil den nye funktion, du tilføjer, referere til funktionerne og variablerne i dit bibliotek i stedet for at bruge dem i postgresql-hovedprogrammet. Det refererer sandsynligvis til datastrukturer, som ikke er korrekt initialiseret, hvilket får det til at gå ned.

Jeg anbefaler, at du starter med en tom fil og kun kopierer funktionen int2_avg_accum fra numeric.c (omdøbt som du har gjort). Hvis den funktion kalder andre funktioner i postgresql, eller refererer til variabler, vil den bruge funktionerne og variablerne i postgresql-hovedbinæren, hvilket er det, du ønsker. Du kan #inkludere den originale numeric.h for at få erklæringerne for alle de eksterne funktioner.

Der er nogle andre forskelle mellem, hvordan funktionen er defineret som en intern funktion, og hvordan den skal defineres, når den indlæses som et dynamisk indlæst modul:

  • Du skulle angive, at du bruger V1-kaldekonventionen ved at tilføje makroen:

    PG_FUNCTION_INFO_V1(int2_avg_accum2);

    Hvis det mangler, vil dette også forårsage segfaults, fordi postgresql vil antage version 0 kaldende konventioner, som ikke matcher funktionsdefinitionen!

  • Som du har angivet, skal du inkludere PG_MODOULE_MAGIC.

Den komplette fil, som fungerede for mig, er:

#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);
}

Kompileret med:

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

Jeg brugte Postgresql 9.2 på Centos 6. Du skal muligvis justere dine stier i henhold til din opsætning.




  1. CakePHP rekursiv sletning

  2. Problemer med T-SQL TRY CATCH?

  3. en effektiv måde at teste, om der findes en tabelrække

  4. Benchmarking af manuelle databaseimplementeringer vs. automatiserede implementeringer