sql >> Databáze >  >> RDS >> PostgreSQL

Vytvořte kopii interní C funkce PostgreSQL a načtěte ji jako uživatelsky definovanou funkci

Důvod, proč se klient psql ptá, zda se chcete znovu připojit, je ten, že backend je segfaulting, jak je uvedeno v komentářích.

Bylo by možné shromáždit výpis jádra z takové havárie a prozkoumat jej pomocí debuggeru (např. gdb), abyste zjistili, kde přesně havaruje. Nejlépe však odhaduji, že se hroutí, protože jste vzali velký soubor napsaný jako základní součást postgresql, zkompilovali jste jej samostatně a pokusili se jej načíst jako rozšiřující modul.

Soubor numeric.c obsahuje obrovské množství funkcí, statických proměnných a datových struktur, z nichž se snažíte duplikovat pouze jednu. Všechny tyto funkce, proměnné atd. již existují v běžícím systému postgresql. Když zkompilujete svou verzi numeric.c a načtete ji, nová funkce, kterou přidáváte, bude odkazovat na funkce a proměnné ve vaší knihovně namísto použití těch v hlavním programu postgresql. Pravděpodobně odkazuje na datové struktury, které nejsou správně inicializovány, což způsobuje selhání.

Doporučuji začít s prázdným souborem a zkopírovat pouze funkci int2_avg_accum z numeric.c (přejmenovanou, jak jste to udělali). Pokud tato funkce volá jiné funkce v postgresql nebo odkazuje na proměnné, použije funkce a proměnné v hlavním binárním souboru postgresql, což je to, co chcete. Můžete #include původní numeric.h získat deklarace všech externích funkcí.

Existují některé další rozdíly mezi tím, jak je funkce definována jako interní funkce, a tím, jak je třeba ji definovat při načítání jako dynamicky načítaný modul:

  • Museli jste zadat, že používáte konvenci volání V1 přidáním makra:

    PG_FUNCTION_INFO_V1(int2_avg_accum2);

    Pokud to chybí, způsobí to také chyby segfault, protože postgresql bude předpokládat konvence volání verze 0, což neodpovídá definici funkce!

  • Jak jste uvedli, musíte zahrnout PG_MODOULE_MAGIC.

Kompletní soubor, který mi fungoval, je:

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

Zkompilováno s:

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

Používal jsem Postgresql 9.2 na Centos 6. Možná budete muset upravit své cesty podle vašeho nastavení.




  1. Oracle převádí RAW do formátu data

  2. mysql, transponovat/pivotovat řádek do sloupce, výběr proměnných

  3. Převeďte čas Javascriptu do formátu MySQL pomocí PHP

  4. Jak vytvořit sekvenci, pokud neexistuje