PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Crie uma cópia da função C interna do PostgreSQL e carregue-a como função definida pelo usuário


A razão pela qual o cliente psql está perguntando se você deseja se reconectar é porque o backend está com falha de segmentação, conforme os comentários.

Seria possível coletar um dump de memória de tal travamento e examiná-lo com um depurador (por exemplo, gdb) para descobrir exatamente onde está travando. No entanto, meu melhor palpite é que ele está travando porque você pegou um arquivo grande escrito como um componente principal do postgresql, compilou-o separadamente e tentou carregá-lo como um módulo de extensão.

O arquivo numeric.c contém um grande número de funções, variáveis ​​estáticas e estruturas de dados, das quais você está tentando duplicar apenas uma. Todas essas funções, variáveis, etc já existem no sistema postgresql em execução. Quando você compila sua versão de numeric.c e a carrega, a nova função que você está adicionando estará referenciando as funções e variáveis ​​em sua biblioteca ao invés de usar aquelas no programa postgresql principal. Provavelmente está fazendo referência a estruturas de dados que não foram inicializadas corretamente, causando o travamento.

Eu recomendo que você comece com um arquivo em branco e copie apenas a função int2_avg_accum de numeric.c (renomeado como você fez). Se essa função estiver chamando outras funções no postgresql, ou referenciando variáveis, ela usará as funções e variáveis ​​no binário postgresql principal, que é o que você deseja. Você pode #include o numeric.h original para obter as declarações de todas as funções externas.

Existem algumas outras diferenças entre como a função é definida como uma função interna e como ela precisa ser definida quando carregada como um módulo carregado dinamicamente:

  • Você precisava especificar que está usando a convenção de chamada V1 adicionando a macro:

    PG_FUNCTION_INFO_V1(int2_avg_accum2);

    Se faltar, isso também causará falhas de segmentação porque o postgresql assumirá as convenções de chamada da versão 0, que não correspondem à definição da função!

  • Como você indicou, você deve incluir o PG_MODOULE_MAGIC.

O arquivo completo, que funcionou para mim, é:
#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);
}

Compilado com:
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

Eu estava usando o Postgresql 9.2 no Centos 6. Você pode precisar ajustar seus caminhos de acordo com sua configuração.