PostgreSQL 外部动态连接库魔法块的使用
最常见的一种方式
CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean AS 'os_libpath', 'c_funcname' LANGUAGE C STRICT;
文档中提到两种调用习惯 V0 和 V1,从代码里边看,V0已经不再支持。
这里不去考虑函数定义方法,着重看 MAGIC 定义,相信很多朋友遇到过这个错误:
ereport(ERROR, (errmsg("incompatible library \"%s\": missing magic block", libname), errhint("Extension libraries are required to use the PG_MODULE_MAGIC macro.")));
这是没有在外部库里边引入 magic data 引起的,它定义在 fmgr.h 中:
/* The actual data block contents */ #define PG_MODULE_MAGIC_DATA \ { \ sizeof(Pg_magic_struct), \ PG_VERSION_NUM / 100, \ FUNC_MAX_ARGS, \ INDEX_MAX_KEYS, \ NAMEDATALEN, \ FLOAT4PASSBYVAL, \ FLOAT8PASSBYVAL \ } /* * Declare the module magic function. It needs to be a function as the dlsym * in the backend is only guaranteed to work on functions, not data */ typedef const Pg_magic_struct *(*PGModuleMagicFunction) (void); #define PG_MAGIC_FUNCTION_NAME Pg_magic_func #define PG_MAGIC_FUNCTION_NAME_STRING "Pg_magic_func" #define PG_MODULE_MAGIC \ extern PGDLLEXPORT const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \ const Pg_magic_struct * \ PG_MAGIC_FUNCTION_NAME(void) \ { \ static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \ return &Pg_magic_data; \ } \ extern int no_such_variable
载入外部库时,首先检查有没有 "Pg_magic_func" 函数,如果有将它的返回值与当前数据库内核定义作比较,如果不符合就会报错,具体逻辑请看 src/backend/utils/fmgr/dfmgr.c 中定义的 internal_load_library 函数 源代码。