Powodem, dla którego klient psql pyta, czy chcesz ponownie się połączyć, jest to, że backend działa w trybie segfault, jak w komentarzach.
Możliwe byłoby zebranie zrzutu pamięci z takiej awarii i zbadanie go debuggerem (np. gdb), aby dowiedzieć się, gdzie dokładnie się awaria. Jednak domyślam się, że się zawiesza, ponieważ wziąłeś duży plik napisany jako główny komponent postgresql, skompilowałeś go osobno i próbowałeś załadować jako moduł rozszerzenia.
Plik numeric.c zawiera ogromną liczbę funkcji, zmiennych statycznych i struktur danych, z których próbujesz zduplikować tylko jedną. Wszystkie te funkcje, zmienne itp. już istnieją w działającym systemie postgresql. Kiedy skompilujesz swoją wersję numeric.c i załadujesz ją, nowa funkcja, którą dodasz, będzie odwoływać się do funkcji i zmiennych w twojej bibliotece, zamiast używać tych w głównym programie postgresql. Prawdopodobnie odwołuje się do struktur danych, które nie zostały prawidłowo zainicjowane, powodując awarię.
Zalecam rozpoczęcie od pustego pliku i skopiowanie tylko funkcji int2_avg_accum z numeric.c (zmienionej nazwy, tak jak zrobiłeś). Jeśli ta funkcja wywołuje inne funkcje w postgresql lub odwołuje się do zmiennych, użyje funkcji i zmiennych z głównego pliku binarnego postgresql, a tego właśnie chcesz. Możesz #dołączyć oryginalny numeric.h, aby uzyskać deklaracje wszystkich funkcji zewnętrznych.
Istnieje kilka innych różnic między tym, jak funkcja jest zdefiniowana jako funkcja wewnętrzna, a tym, jak należy ją zdefiniować, gdy jest ładowana jako moduł ładowany dynamicznie:
-
Musisz określić, że używasz konwencji wywoływania V1, dodając makro:
PG_FUNCTION_INFO_V1(int2_avg_accum2);
Jeśli nie, spowoduje to również segfaulty, ponieważ postgresql przyjmie konwencje wywoływania wersji 0, które nie są zgodne z definicją funkcji!
-
Jak wskazałeś, musisz dołączyć PG_MODOULE_MAGIC.
Kompletny plik, który zadziałał dla mnie, to:
#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);
}
Skompilowany z:
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
Używałem Postgresql 9.2 na Centos 6. Być może trzeba będzie dostosować ścieżki zgodnie z konfiguracją.