本篇主要讲解使用C语言开发PostgreSQL服务端应用(libpq、自定义函数、扩展)常用到的结构及宏定义。以 pgpool-recovery扩展分析 中的C语言源代码为例,顺序拆解使用到的结构体及宏定义。
PG_MODULE_MAGIC宏
作用:支持验证已加载模块的后端兼容性。
用C语言开发扩展或者自定义函数时要求动态加载的模块包括宏调用PG_MODULE_MAGIC以便检查明显的不兼容性,比如在不同主版本的PostgreSQL下编译。
要在不支持PG_MODULE_MAGIC的PostgreSQL版本进行编译,可以将其包裹在#ifdef/#endif里测试。需要注意的是,在一个有多个源文件的模块中,此宏调用只能出现一次。
magic块中包含的特定项是可自定义配置的,并且如果使用其他值编译动态加载模块,则有可能破坏这些模块。此外,长度字段可用于检测定义更改。
注意:我们会使用memcpy()比较magic块,因此最好不要对其做对齐填充。
注意:更改magic块时,请务必调整dfmgr.c中的incompatible_module_error()函数。
/* magic block structure */typedefstruct{ intlen; /* sizeof(this struct) */intversion; /* PostgreSQL major version */intfuncmaxargs; /* FUNC_MAX_ARGS */intindexmaxkeys; /* INDEX_MAX_KEYS */intnamedatalen; /* NAMEDATALEN */intfloat8byval; /* FLOAT8PASSBYVAL */charabi_extra[32]; /* see pg_config_manual.h */} Pg_magic_struct; /* * 生成实际的数据块内容 * PG_VERSION_NUM - 在pg_config.h中定义,本例是150002* FUNC_MAX_ARGS - 在pg_config_manual.h中定义,缺省值是100* INDEX_MAX_KEYS - 在pg_config_manual.h中定义,缺省值是32* NAMEDATALEN - 在pg_config_manual.h中定义,缺省值是64* FLOAT8PASSBYVAL - 在c.h中定义,缺省值是true* FMGR_ABI_EXTRA - pg_config_manual.h中定义,缺省值是"PostgreSQL"*//* FMGR_ABI_EXTRA自义在pg_config_manual.h中* 内容为 "PostgreSQL"*/StaticAssertDecl(sizeof(FMGR_ABI_EXTRA) <=sizeof(((Pg_magic_struct*) 0)->abi_extra), "FMGR_ABI_EXTRA too long"); /** 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*/typedefconstPg_magic_struct*(*PGModuleMagicFunction) (void);
根据以上的定义,宏PG_MODULE_MAGIC在翻译时会被展开成如下代码:
externPGDLLEXPORTconstPg_magic_struct*Pg_magic_func(void); constPg_magic_struct*Pg_magic_func(void) { staticconstPg_magic_structPg_magic_data= { sizeof(Pg_magic_struct), 150002/100, 100, 32, 64, 1, "PostgreSQL", }; return&Pg_magic_data; } externintno_such_variable
PG_FUNCTION_INFO_V1
动态加载函数调用约定检测支持
在fmgr.h中定义。动态加载函数当前仅支持Version-1,不再支持Version-0。
typedefstruct{ intapi_version; /* 指定调用约定版本 *//* More fields may be added later, for version numbers > 1. */} Pg_finfo_record; /* info函数的签名 */typedefconstPg_finfo_record*(*PGFInfoFunction) (void);
以pgpool-recovery扩展的PG_FUNCTION_INFO_V1(pgpool_recovery)为例,通过宏展开后代码如下:
/** 所有可被fmgr直接调用的函数必须有如下签名,相关struct以后讲*/typedefstructFunctionCallInfoBaseData*FunctionCallInfo; typedefDatum (*PGFunction) (FunctionCallInfofcinfo); externDatumpgpool_recovery(FunctionCallInfofcinfo); externPGDLLEXPORTconstPg_finfo_record*pg_finfo_pgpool_recovery(void) { staticconstPg_finfo_recordmy_finfo= { 1 }; return&my_finfo; } externintno_such_variable