pg_language表定义了函数实现所使用的语言。主要支持了C语言和SQL语句。一些可选的语言包括pl/pgsql、tcl和perl。sql
ligang=# select lanname, lanispl, lanpltrusted, lanplcallfoid, laninline, lanvalidator from pg_language; lanname | lanispl | lanpltrusted | lanplcallfoid | laninline | lanvalidator ----------+---------+--------------+---------------+-----------+-------------- internal | f | f | 0 | 0 | 2246 c | f | f | 0 | 0 | 2247 sql | f | t | 0 | 0 | 2248 plpgsql | t | t | 13198 | 13199 | 13200
pg_proc表对函数进行了定义。每个函数在该表中都对应一个元组,包含函数名。输入参数类型,返回类型以及对函数的定义(多是文本,多是一段编译型语句,也多是对可执行代码的引用)。编译过的函数能够静态地连接到服务器上,或者在存储在共享库内,当第一次使用该库时动态的载入。数据库
ligang=# select proname,prolang, prorettype,proargtypes, prosrc,probin from pg_proc where proname like '%square%'; proname | prolang | prorettype | proargtypes | prosrc | probin ---------+---------+------------+-------------+----------------------------+-------------------- square | 13201 | 23 | 23 | begin return $1 * $1; end; | squares | 13 | 23 | 23 | squares_return_int | $libdir/squares.so
查看其数据类型centos
ligang=# select oid , typname from pg_type where oid = 23; oid | typname -----+--------- 23 | int4 (1 row)
如下是示例函数:服务器
C: 与内建SQL类型等效的C类型ide
int square_int (int x) { return x * x; }
把上面的函数编译成共享库文件,这样声明:函数
CREATE FUNCTION square(int) RETURNS int AS '/path/to/square.so', 'square_int' LANGUAGE 'C';
PL/PGSQL:post
ligang=# create function square(int) returns int as 'begin return $1 * $1; end;' LANGUAGE 'plpgsql'; CREATE FUNCTION ligang=# ligang=# ligang=# select square(4); square -------- 16
创建用户函数动态库测试
新建代码
#include "postgres.h"
#include "fmgr.h"fetch
int square_int(int x) { return x * x; }
编译 - 添加共享库this
[ligang@yfslcentos71 include]$ gcc -I`pg_config --includedir-server` -c squares.c [ligang@yfslcentos71 include]$ gcc -shared squares.o -o squares.so [ligang@yfslcentos71 include]$ cp squares.so `pg_config --libdir`/
Pg数据库装载
ligang=# create function squares(int) returns int as '$libdir/squares.so', 'square_int' LANGUAGE 'c' STRICT;
关于PG_MODULE_MAGIC
为了确保不会错误加载共享库文件,从PostgreSQL 开始将检查那个文件的"magic block",这容许服务器以检查明显的不兼容性。
#ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif
若是不打算兼容8.2 PostgreSQL以前的版本, #ifdef测试也能够省略
源码修改成:
#include "postgres.h" #include "fmgr.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif int square_int(int x) { return x * x; }
版本约定
版本0约定
版本-0方法中,此风格 C 函数的参数和结果用普通 C 风格声明, 可是要当心使用上面显示的 SQL 数据类型的 C 表现形式。 (之前版本;)
#include "postgres.h" #include "fmgr.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif int square_int(int x) { return x * x; }
版本1约定 (应当使用该版本)
版本-1调用约定使用宏消除大多数传递参数和结果的复杂性。版本-1风格函数的C定义老是下面这样:
Datum funcname(PG_FUNCTION_ARGS);
另外,宏调用:
PG_FUNCTION_INFO_V1(funcname);
也必须出如今同一个源文件里(一般就能够写在函数自身前面)。 对那些internal语言函数而言,不须要调用这个宏, 由于PostgreSQL目前假设内部函数都是版本-1。不过,对于动态加载的函数, 它是必须的。
每一个实际参数都是用一个对应该参数的数据类型的 PG_GETARG_xxx()宏抓取的, 用返回类型的PG_RETURN_xxx()宏返回结果。 PG_GETARG_xxx()接受要抓取的函数参数的编号 (从 0 开始)做为其参数。PG_RETURN_xxx() 接受实际要返回的数值为自身的参数。
关于PG_GETARG_XXX 定义于 src/include/fmgr.h
/* Macros for fetching arguments of standard types */ #define PG_GETARG_DATUM(n) (fcinfo->arg[n]) #define PG_GETARG_INT32(n) DatumGetInt32(PG_GETARG_DATUM(n)) #define PG_GETARG_UINT32(n) DatumGetUInt32(PG_GETARG_DATUM(n)) #define PG_GETARG_INT16(n) DatumGetInt16(PG_GETARG_DATUM(n)) #define PG_GETARG_UINT16(n) DatumGetUInt16(PG_GETARG_DATUM(n)) #define PG_GETARG_CHAR(n) DatumGetChar(PG_GETARG_DATUM(n)) #define PG_GETARG_BOOL(n) DatumGetBool(PG_GETARG_DATUM(n)) #define PG_GETARG_OID(n) DatumGetObjectId(PG_GETARG_DATUM(n)) #define PG_GETARG_POINTER(n) DatumGetPointer(PG_GETARG_DATUM(n)) #define PG_GETARG_CSTRING(n) DatumGetCString(PG_GETARG_DATUM(n)) #define PG_GETARG_NAME(n) DatumGetName(PG_GETARG_DATUM(n)) /* these macros hide the pass-by-reference-ness of the datatype: */ #define PG_GETARG_FLOAT4(n) DatumGetFloat4(PG_GETARG_DATUM(n)) #define PG_GETARG_FLOAT8(n) DatumGetFloat8(PG_GETARG_DATUM(n)) #define PG_GETARG_INT64(n) DatumGetInt64(PG_GETARG_DATUM(n)) /* use this if you want the raw, possibly-toasted input datum: */ #define PG_GETARG_RAW_VARLENA_P(n) ((struct varlena *) PG_GETARG_POINTER(n)) /* use this if you want the input datum de-toasted: */ #define PG_GETARG_VARLENA_P(n) PG_DETOAST_DATUM(PG_GETARG_DATUM(n)) /* and this if you can handle 1-byte-header datums: */ #define PG_GETARG_VARLENA_PP(n) PG_DETOAST_DATUM_PACKED(PG_GETARG_DATUM(n))
代码
#include "postgres.h" #include "fmgr.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif PG_FUNCTION_INFO_V1(squares_return_int); Datum squares_return_int(PG_FUNCTION_ARGS) { int32 arg = PG_GETARG_INT32(0); PG_RETURN_INT32(arg * arg); }
编译
[ligang@yfslcentos71 include]$ gcc -I`pg_config --includedir-server` -c squares.c [ligang@yfslcentos71 include]$ gcc -shared squares.o -o squares.so /usr/bin/ld: squares.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC squares.o: could not read symbols: Bad value [ligang@yfslcentos71 include]$ gcc -I`pg_config --includedir-server` -fPIC -c squares.c [ligang@yfslcentos71 include]$ gcc -shared squares.o -o squares.so [ligang@yfslcentos71 include]$ [ligang@yfslcentos71 include]$ cp squares.so `pg_config --libdir`/
SQL声明函数
ligang=# create function squares(int) returns int as '$libdir/squares.so', 'squares_return_int' LANGUAGE 'c' STRICT; CREATE FUNCTION
补充
参考Postgresql 9.4手册