创建PostgreSQL内部C函数的副本并将其作为用户定义的函数加载 [英] Create copy of PostgreSQL internal C function and load it as user defined function

查看:64
本文介绍了创建PostgreSQL内部C函数的副本并将其作为用户定义的函数加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建位于 src / backend / utils / adt / numeric.c int2_avg_accum 的修改版本。 $ c>。我以为我可以(首先)编译 numeric.h 并加载 int2_avg_accum 作为用户定义的函数。

I would like to create modified version of C function int2_avg_accum located in src/backend/utils/adt/numeric.c. I thought I can (as a start) just compile numeric.h and load int2_avg_accum as user defined function.

我做了什么:


  1. 添加了 PG_MODULE_MAGIC numeric.h (如此处

  2. int2_avg_accum 重命名为 int2_avg_accum2 numeric.h
  3. 中的c $ c>
  4. 已编译为 numeric.h 的形式文档中描述的内容(无错误,无警告)( cc -fpic -I pg_config --includedir-server -c numeric.c ,然后 cc -shared -o numeric.so numeric.o

  5. 在PostgreSQL中创建一个函数:

  1. Added PG_MODULE_MAGIC to numeric.h (as described here)
  2. Renamed int2_avg_accum to int2_avg_accum2 in numeric.h
  3. Compiled numeric.h as described in the documentation (no errors, no warnings) (cc -fpic -Ipg_config --includedir-server-c numeric.c and then cc -shared -o numeric.so numeric.o)
  4. Created a function in PostgreSQL:

create or replace function int2_avg_accum2(bigint[], smallint)
  returns bigint[] as
'/usr/lib/postgresql/9.1/lib/numeric', 'int2_avg_accum2'
  language c
  cost 1;
alter function int2_avg_accum2(bigint[], smallint)
  owner to postgres;

当我尝试运行时,选择int2_avg_accum2(array [1 :: bigint, 1],1 :: smallint); 我仅收到一条消息(在pgAdmin中):是否要尝试重新连接到数据库?。没有其他消息或错误。

When I try to run select int2_avg_accum2(array[1::bigint,1],1::smallint); I get only message (in pgAdmin): "Do you want to attempt to reconnect to the database?". No other messages or errors.

调用函数时,我在 /var/log/postgresql/postgresql-9.1-main.log

2013-12-03 09:52:02 CET LOG:  server process (PID 3366) was terminated by signal 11: Segmentation fault
2013-12-03 09:52:02 CET LOG:  terminating any other active server processes
2013-12-03 09:52:02 CET WARNING:  terminating connection because of crash of another server process
2013-12-03 09:52:02 CET DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2013-12-03 09:52:02 CET HINT:  In a moment you should be able to reconnect to the database and repeat your command.
2013-12-03 09:52:02 CET LOG:  all server processes terminated; reinitializing
2013-12-03 09:52:02 CET LOG:  database system was interrupted; last known up at 2013-12-03 09:50:53 CET
2013-12-03 09:52:02 CET LOG:  database system was not properly shut down; automatic recovery in progress
2013-12-03 09:52:02 CET LOG:  record with zero length at 0/B483EA0
2013-12-03 09:52:02 CET LOG:  redo is not required
2013-12-03 09:52:03 CET LOG:  autovacuum launcher started
2013-12-03 09:52:03 CET LOG:  database system is ready to accept connections

为了获得 int2_avg_accum 的工作副本,我必须做不同的事情?

What I have to do differently in order to get working copy of int2_avg_accum?

推荐答案

psql客户端询问您是否希望重新连接的原因是,根据注释,后端存在段错误。

The reason the psql client is asking if you wish to reconnect is because the backend is segfaulting, as per the comments.

可以从此类崩溃中收集核心转储,并使用调试器(例如gdb)对其进行检查,以找出崩溃的确切位置。但是,我最好的猜测是它崩溃了,因为您已将一个大文件写为postgresql的核心组件,将其单独编译,然后尝试将其作为扩展模块加载。

It would be possible to collect a core dump from such a crash and examine it with a debugger (eg. gdb) to find out exactly where it is crashing. However, my best guess is that it is crashing because you have taken a big file written to be a core component of postgresql, compiled it up separately, and attempted to load it in as an extension module.

文件numeric.c包含大量函数,静态变量和数据结构,您仅尝试复制其中的一个。所有这些函数,变量等已经存在于正在运行的postgresql系统中。当您编译numeric.c版本并加载它时,要添加的新函数将引用库中的函数和变量,而不是在主postgresql程序中使用它们。

The file numeric.c contains a huge number of functions, static variables and data structures, of which you are trying to duplicate only one. All of these functions, variables, etc already exist in the running postgresql system. When you compile up your version of numeric.c and load it, the new function you are adding will be referencing the functions and variables in your library instead of using those in the main postgresql program. It is probably referencing data structures which are not properly initialized, causing it to crash.

我建议您从一个空白文件开始,仅从数字中复制int2_avg_accum函数。 c(重新命名)。如果该函数正在postgresql中调用其他函数或引用变量,它将使用您想要的主要postgresql二进制文件中的函数和变量。您可以#include原始的numeric.h来获取所有外部函数的声明。

I recommend you start with a blank file and copy in only the int2_avg_accum function from numeric.c (renamed as you have done). If that function is calling other functions in postgresql, or referencing variables, it will use the functions and variables in the main postgresql binary, which is what you want. You can #include the original numeric.h to get the declarations of all of the external functions.

将函数定义为内部函数的方式还有一些其他区别以及作为动态加载的模块加载时如何定义它:

There are some other differences between how the function is defined as an internal function and how it needs to be defined when loaded as a dynamically loaded module:


  • 您需要指定您正在使用V1调用通过添加宏的约定:

  • You needed to specify that you are using V1 calling convention by adding the macro:

PG_FUNCTION_INFO_V1(int2_avg_accum2);

PG_FUNCTION_INFO_V1(int2_avg_accum2);

如果丢失,这也会导致段错误,因为postgresql将采用版本0的调用约定,该约定与函数定义不匹配!

If missing this will also cause segfaults because postgresql will assume version 0 calling conventions, which does not match the function definition!

如您所指出的,您必须包括PG_MODOULE_MAGIC。

As you indicated you have to include the PG_MODOULE_MAGIC.

对我有用的完整文件是:

The complete file, which worked for me, is:

#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

我在Centos 6上使用了Postgresql 9.2。您可能需要根据设置调整路径。

I was using Postgresql 9.2 on Centos 6. You may need to adjust your paths according to your setup.

这篇关于创建PostgreSQL内部C函数的副本并将其作为用户定义的函数加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆