PostgreSQL是使用C语言进行开发的,一般情况下,大部分的脚本语言会比C语言脚本允许的更慢,另外PostgreSQL的某些功能只能依靠C语言来进行开发,下面介绍一下如何使用C语言在pg进行编程。

我们这里编写一个简单的函数,用来实现两个参数的和的计算。
首先我们需要先编写C源文件,代码如下:

#include "postgres.h"
#include "fmgr.h"

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(add_ab);

Datum
add_ab(PG_FUNCTION_ARGS)
{
        int32 arg_a = PG_GETARG_INT32(0);
        int32 arg_b = PG_GETARG_INT32(1);

        PG_RETURN_INT32(arg_a + arg_b);
}

简单对上面的函数中的内容进行一些介绍:

  • #include“ postgres.h”:包括与Postgres接口所需的大多数基本内容。此行需要包含在每个声明Postgres函数的C文件中。
  • #include“ fmgr.h”:包含需要使用PG_GETARG_XXX和PG_RETURN_XXX宏。
  • PG_MODULE_MAGIC:为了确保动态载入对象文件不会被载入到一个不兼容的服务器, PostgreSQL会检查该文件是否包含一个
    带有合适内容的“magic block”。
  • Datum:是每个C语言Postgres函数的返回类型,可以是任何数据类型。
  • add_ab(PG_FUNCTION_ARGS):add_ab是函数名,PG_FUNCTION_ARGS表示参数可以为任意值,即使函数没有参数也必须加上。
  • PG_GETARG_INT32(0):用来为参数获取值。
  • PG_RETURN_INT32:用来返回函数值。

接下来我们需要编译.c的源文件。这里可以通过Makefile文件来实现,同时我们可以直接利用PostgreSQL扩展程序构建基础(简称PGXS)来实现。

Makefile:

MODULES = add_func

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

MODULES:要从源文件构建的具有相同词干的共享库对象的列表(不要在这个列表中包括库后缀)。
剩下的三行是是PostgreSQL 构建扩展相关的命令,保留就可以。

编写完这两个文件我们就可以使用make命令来编译了。

pg12@oracle-> make
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fPIC -I. -I./ -I/home/pg12/pgsql12.4/include/server -I/home/pg12/pgsql12.4/include/internal  -D_GNU_SOURCE   -c -o add_func.o add_func.c
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -O2 -fPIC add_func.o -L/home/pg12/pgsql12.4/lib   -Wl,--as-needed -Wl,-rpath,'/home/pg12/pgsql12.4/lib',--enable-new-dtags  -shared -o add_func.so
pg12@oracle-> make install
/bin/mkdir -p '/home/pg12/pgsql12.4/lib'
/bin/install -c -m 755  add_func.so '/home/pg12/pgsql12.4/lib/'

编译完之后我们就可以去数据库中直接创建这个函数了:

bill@bill=>create function add(int,int)
bill-# returns int
bill-# as '/home/pg12/pgsql12.4/lib/add_func','add_ab'
bill-# language C strict;
CREATE FUNCTION

使用测试:

bill@bill=>select add(1,2);
 add 
-----
   3
(1 row)

至此一个简单的构建C函数的例子便完成了,但是上面的代码中有一个很大的缺点:移植性不行。因为我们换个环境可能又要根据不同的目录(如上的’/home/pg12/pgsql12.4/lib’)来编写不同的CREATE FUNCTION的命令了。因此我们可以在上面的基础上做一些简单的优化。

我们要编写一个名为add_func.sql.in 的文件,其内容如下:
add_func.sql.in:

create function add(int,int)
        returns int
as 'MODULE_PATHNAME','add_ab'
language C strict;

接着在Makefile中加入DATA_built = add_func.sql:

MODULES = add_func
DATA_built = add_func.sql

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

接下来我们再运行make命令编译时,add_func.sql.in会被编译到add_func.sql文件中,而其中的MODULE_PATHNAME会被真实的路径替换,

pg12@oracle-> make
sed 's,MODULE_PATHNAME,$libdir/add_func,g' add_func.sql.in >add_func.sql

查看下add_func.sql文件:

create function add(int,int)
        returns int
as '$libdir/add_func','add_ab'
language C strict;

那么我们加下来只需要直接执行该文件即可:

bill@bill=>\i ./add_func.sql
CREATE FUNCTION

总结:
在PostgreSQL中编写一个简单的C函数大致过程为:
1、在modulename.c中写C代码。
2、在modulename.sql.in中为CREATE FUNCTION写SQL代码。
3、写一个Makefile 函数。
4、运行make,编译一个C程序并生成modulename.sql
5、运行make install,安装已生成的程序。
6、在psql命令行中执行 \i / /modulename.sql,运行生成的modulename.sql文件。