PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Създайте копие на вътрешна C функция на PostgreSQL и я заредете като дефинирана от потребителя функция

Причината, поради която psql клиентът ви пита дали желаете да се свържете отново, е, че бекендът е segfaulting, според коментарите.

Би било възможно да се събере дъмп на ядрото от такъв срив и да се изследва с дебъгер (напр. gdb), за да се установи точно къде се срива. Най-доброто ми предположение обаче е, че се срива, защото сте взели голям файл, написан като основен компонент на postgresql, компилирали сте го отделно и сте се опитали да го заредите като модул за разширение.

Файлът numeric.c съдържа огромен брой функции, статични променливи и структури от данни, от които се опитвате да дублирате само една. Всички тези функции, променливи и т.н. вече съществуват в работещата система postgresql. Когато компилирате вашата версия на numeric.c и я заредите, новата функция, която добавяте, ще препраща към функциите и променливите във вашата библиотека, вместо да използва тези в основната програма postgresql. Вероятно препраща към структури от данни, които не са правилно инициализирани, което води до срив.

Препоръчвам ви да започнете с празен файл и да копирате само функцията int2_avg_accum от numeric.c (преименувана, както сте направили). Ако тази функция извиква други функции в postgresql или препраща към променливи, тя ще използва функциите и променливите в основния двоичен файл на postgresql, което е, което искате. Можете да #включите оригиналния numeric.h, за да получите декларациите на всички външни функции.

Има някои други разлики между това как функцията е дефинирана като вътрешна функция и как трябва да бъде дефинирана, когато се зарежда като динамично зареден модул:

  • Трябваше да посочите, че използвате конвенция за извикване V1, като добавите макроса:

    PG_FUNCTION_INFO_V1(int2_avg_accum2);

    Ако липсва, това също ще причини segfaults, тъй като postgresql ще приеме конвенции за извикване версия 0, което не отговаря на дефиницията на функцията!

  • Както посочихте, трябва да включите PG_MODOULE_MAGIC.

Пълният файл, който работи за мен, е:

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

Компилиран с:

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

Използвах Postgresql 9.2 на Centos 6. Може да се наложи да коригирате пътищата си според вашата настройка.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Flask before_request и teardown_request за DB връзки

  2. TypeError:Не може да се извика метод 'query' на null - при извикване на pg.connect с Heroku node.js

  3. Postgresql - Основни масиви и array_agg

  4. Фиксиране на дупки/пропуски в числата, генерирани от последователността на Postgres

  5. Как да включите липсващи данни за множество групи в рамките на времевия период?