sql >> Databasteknik >  >> RDS >> PostgreSQL

Skapa kopia av PostgreSQL intern C-funktion och ladda den som användardefinierad funktion

Anledningen till att psql-klienten frågar om du vill återansluta är att backend-delen är segfaulting, enligt kommentarerna.

Det skulle vara möjligt att samla in en kärndump från en sådan krasch och undersöka den med en debugger (t.ex. gdb) för att ta reda på exakt var den kraschar. Min bästa gissning är dock att den kraschar eftersom du har tagit en stor fil skriven för att vara en kärnkomponent i postgresql, kompilerat den separat och försökt ladda in den som en tilläggsmodul.

Filen numeric.c innehåller ett stort antal funktioner, statiska variabler och datastrukturer, av vilka du bara försöker duplicera en. Alla dessa funktioner, variabler etc finns redan i det körande postgresql-systemet. När du kompilerar din version av numeric.c och laddar den, kommer den nya funktionen du lägger till att referera till funktionerna och variablerna i ditt bibliotek istället för att använda dem i postgresql-huvudprogrammet. Det hänvisar förmodligen till datastrukturer som inte är korrekt initierade, vilket gör att den kraschar.

Jag rekommenderar att du börjar med en tom fil och kopierar in endast funktionen int2_avg_accum från numeric.c (döpt om som du har gjort). Om den funktionen anropar andra funktioner i postgresql, eller refererar till variabler, kommer den att använda funktionerna och variablerna i postgresql-binären, vilket är vad du vill ha. Du kan #inkludera den ursprungliga numeric.h för att få deklarationerna för alla externa funktioner.

Det finns några andra skillnader mellan hur funktionen definieras som en intern funktion och hur den behöver definieras när den laddas som en dynamiskt laddad modul:

  • Du behövde ange att du använder V1-anropskonventionen genom att lägga till makrot:

    PG_FUNCTION_INFO_V1(int2_avg_accum2);

    Om det saknas kommer detta också att orsaka segfaults eftersom postgresql kommer att anta version 0 anropskonventioner, vilket inte matchar funktionsdefinitionen!

  • Som du angav måste du inkludera PG_MODOULE_MAGIC.

Den fullständiga filen, som fungerade för mig, är:

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

Sammanställt 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

Jag använde Postgresql 9.2 på Centos 6. Du kan behöva justera dina sökvägar enligt dina inställningar.




  1. Hur man snabbar på insättning från pandas.DataFrame .to_sql

  2. Analysera ett datum från oformaterad text i SQL

  3. Hur får man en primärnyckel med nollvärden med hjälp av tom sträng?

  4. Kan jag använda VARCHAR som PRIMÄRNYCKEL?