PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Erstellen Sie eine Kopie der internen C-Funktion von PostgreSQL und laden Sie sie als benutzerdefinierte Funktion

Der Grund, warum der psql-Client fragt, ob Sie die Verbindung wiederherstellen möchten, ist, dass das Backend gemäß den Kommentaren segfaulting ist.

Es wäre möglich, einen Core-Dump von einem solchen Absturz zu sammeln und ihn mit einem Debugger (z. B. gdb) zu untersuchen, um herauszufinden, wo genau er abstürzt. Meine beste Vermutung ist jedoch, dass es abstürzt, weil Sie eine große Datei, die als Kernkomponente von postgresql geschrieben wurde, separat kompiliert und versucht haben, sie als Erweiterungsmodul zu laden.

Die Datei numeric.c enthält eine riesige Anzahl von Funktionen, statischen Variablen und Datenstrukturen, von denen Sie versuchen, nur eine zu duplizieren. Alle diese Funktionen, Variablen usw. sind bereits im laufenden Postgresql-System vorhanden. Wenn Sie Ihre Version von numeric.c kompilieren und laden, referenziert die neue Funktion, die Sie hinzufügen, die Funktionen und Variablen in Ihrer Bibliothek, anstatt die im postgresql-Hauptprogramm zu verwenden. Es verweist wahrscheinlich auf Datenstrukturen, die nicht richtig initialisiert sind, was zum Absturz führt.

Ich empfehle Ihnen, mit einer leeren Datei zu beginnen und nur die Funktion int2_avg_accum aus numeric.c zu kopieren (umbenannt, wie Sie es getan haben). Wenn diese Funktion andere Funktionen in Postgresql aufruft oder auf Variablen verweist, verwendet sie die Funktionen und Variablen in der Hauptbinärdatei von Postgresql, was Sie möchten. Sie können die ursprüngliche numeric.h #einschließen, um die Deklarationen aller externen Funktionen zu erhalten.

Es gibt einige andere Unterschiede zwischen der Definition der Funktion als interne Funktion und der Definition, wie sie definiert werden muss, wenn sie als dynamisch geladenes Modul geladen wird:

  • Sie mussten angeben, dass Sie die V1-Aufrufkonvention verwenden, indem Sie das Makro hinzufügen:

    PG_FUNCTION_INFO_V1(int2_avg_accum2);

    Wenn dies fehlt, führt dies ebenfalls zu Segfaults, da postgresql Version 0-Aufrufkonventionen annimmt, was nicht mit der Funktionsdefinition übereinstimmt!

  • Wie Sie angegeben haben, müssen Sie das PG_MODOULE_MAGIC.

    einschließen

Die vollständige Datei, die für mich funktioniert hat, ist:

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

Kompiliert mit:

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

Ich habe Postgresql 9.2 auf Centos 6 verwendet. Möglicherweise müssen Sie Ihre Pfade entsprechend Ihrer Einrichtung anpassen.