PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Utwórz kopię wewnętrznej funkcji PostgreSQL w języku C i załaduj ją jako funkcję zdefiniowaną przez użytkownika

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ą.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Konwertuj CamelCase na snake_case

  2. Upuść ograniczenie według nazwy w Postgresql

  3. zamień wyraźną wartość kolumn w wiersze postgres

  4. tworzenie pseudopowiązanej listy w sql

  5. Jak porównywać wydajność PostgreSQL za pomocą Sysbench