sql >> Base de Datos >  >> RDS >> PostgreSQL

Cree una copia de la función C interna de PostgreSQL y cárguela como función definida por el usuario

La razón por la que el cliente psql le pregunta si desea volver a conectarse es porque el backend está fallando, según los comentarios.

Sería posible recopilar un volcado del núcleo de un bloqueo de este tipo y examinarlo con un depurador (p. ej., gdb) para averiguar exactamente dónde se bloquea. Sin embargo, mi mejor suposición es que se está bloqueando porque tomó un archivo grande escrito para ser un componente central de postgresql, lo compiló por separado e intentó cargarlo como un módulo de extensión.

El archivo numeric.c contiene una gran cantidad de funciones, variables estáticas y estructuras de datos, de las cuales intenta duplicar solo una. Todas estas funciones, variables, etc. ya existen en el sistema postgresql en ejecución. Cuando compile su versión de numeric.c y la cargue, la nueva función que está agregando hará referencia a las funciones y variables en su biblioteca en lugar de usarlas en el programa principal de postgresql. Probablemente esté haciendo referencia a estructuras de datos que no se han inicializado correctamente, lo que hace que se bloquee.

Le recomiendo que comience con un archivo en blanco y copie solo la función int2_avg_accum de numeric.c (renombrada como lo ha hecho). Si esa función llama a otras funciones en postgresql o hace referencia a variables, usará las funciones y variables en el binario principal de postgresql, que es lo que desea. Puede #incluir el numeric.h original para obtener las declaraciones de todas las funciones externas.

Hay algunas otras diferencias entre cómo se define la función como una función interna y cómo debe definirse cuando se carga como un módulo cargado dinámicamente:

  • Debe especificar que está utilizando la convención de llamadas V1 agregando la macro:

    PG_FUNCTION_INFO_V1(int2_avg_accum2);

    Si falta esto, también causará errores de segmentación porque postgresql asumirá las convenciones de llamada de la versión 0, ¡lo que no coincide con la definición de la función!

  • Como indicaste tienes que incluir el PG_MODOULE_MAGIC.

El archivo completo, que funcionó para mí, es:

#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 con:

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

Estaba usando Postgresql 9.2 en Centos 6. Es posible que deba ajustar sus rutas de acuerdo con su configuración.