+++ title = "将PostgreSQL插件移植到openGauss指导" date = "2021-08-10" tags = ["openGauss插件化架构"] archives = "2021-08" author = "chenxiaobin" summary = "将PostgreSQL插件移植到openGauss指导" img = "/zh/post/chenxiaobin/title/img.png" times = "16:30" +++
PostgreSQL社区提供了丰富的插件,但由于openGauss和PostgreSQL存在一定的差异,如线程/进程模型、系统表和视图等,无法直接为openGauss所用,不可避免的需要在插件上做整改。
本文档主要对Postgresql插件移植到openGauss的过程提供指导说明,旨在让开发人员对PG插件所需要的修改有一个具体的了解,基于该文档,可基本实现PG插件移植到openGauss。
由于openGauss与PostgreSQL在内核上存在不少差异,这篇文档未能覆盖所有这些差异,因此仅依赖该文档有可能无法实现PG插件的完全迁移,部分差异需要开发者深入内核源码识别,然后可将识别出来的差异补充到该博客的第9章对应小节的表格中(博客对应的gitee地址:将PostgreSQL插件移植到openGauss指导,具体操作可见blog仓库的README.md
),有任何问题可在博客下方留言讨论。
将PG插件的代码拷贝到openGauss源码的contrib目录下
配置环境变量,需要将数据库的bin和lib加在操作系统的环境变量PATH和LD_LIBRARY_PATH中
到插件目录下,执行make && make install
,编译安装插件。
编译成功后,到数据库中执行create extension extension_name
即可使用。
通常步骤3和4不会直接成功,需要一些必须的修改。下面分类别说明移植PG插件所需要做的修改。
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/pg_freespacemap
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
override CPPFLAGS :=$(filter-out -fPIE, $(CPPFLAGS)) -fPIC
buffer = palloc(MAX_LINESIZE); -> buffer = (char*)palloc(MAX_LINESIZE);
extern PGDLLEXPORT Datum orafce_to_char_timestamp(PG_FUNCTION_ARGS); ->
extern "C" PGDLLEXPORT Datum orafce_to_char_timestamp(PG_FUNCTION_ARGS);
可以通过nm -D so文件查看生成的符号。
#define check_memcpy_s(r) securec_check_c((r), "", "")
#define check_memmove_s(r) securec_check_c((r), "", "")
#define check_memset_s(r) securec_check_c((r), "", "")
#define check_strcpy_s(r) securec_check_c((r), "", "")
#define check_strncpy_s(r) securec_check_c((r), "", "")
#define check_strcat_s(r) securec_check_c((r), "", "")
#define check_strncat_s(r) securec_check_c((r), "", "")
#define check_gets_s(r) securec_check_ss_c((r), "", "")
#define check_sprintf_s(r) securec_check_ss_c((r), "", "")
#define check_snprintf_s(r) securec_check_ss_c((r), "", "")
#define check_scanf_s(r) securec_check_ss_c((r), "", "")
下面是安全函数整改的示例。
memcpy(d, u, clen); -> check_memcpy_s(memcpy_s(d, strlen(d), u, clen));
为了方便和完全地作安全函数整改,这里提供一个查找危险函数的正则表达式。
(wmemcpy\()|(wmemove\()|(memmove\()|(wcscpy\()|(wcsncpy\()|(strcat\()|(wcscat\()|(strncat\()|(wcsncat\()|(strtok\()|(wcstok\()|(sprintf\()|(swprintf\()|(vsprintf\()|(vswprintf\()|(snprintf\()|(vsnprintf\()|(vsnprintf_truncated\()|(snprintf_truncated\()|(scanf\()|(wscanf\()|(vscanf\()|(vwscanf\()|(fscanf\()|(fwscanf\()|(vfscanf\()|(vfwscanf\()|(sscanf\()|(swscanf\()|(vsscanf\()|(vswscanf\()|(gets\()|(strcpy\()|(strcpy\()|(strncpy\()|(strncpy\()|(strcat\()|(strncat\()|(memcpy\()|(memcpy\()|(memset\()|(memset\()
econtext = error_context_stack; -> econtext = t_thrd.log_cxt.error_context_stack;
a. 如果不考虑在线程池模式下使用插件,将全局变量修改为THR_LOCAL变量,即线程变量,因为用户会话进来会创建一个独立的线程。
b. 如果需要线程池,就需要作额外的修改。线程池模式下,一个用户会话可能会切换多个线程,单纯的将全局变量改为线程变量,在切换线程时会丢失对该变量的修改。openGauss提供了插件自定义会话变量的方式,具体实现如下。(以dblink为例)
extension_session_vars_array
,和标识数组大小的变量extension_session_vars_array_size
,数组用于存放插件会话变量的结构体。typedef struct knl_session_attr_common {
…
uint32 extension_session_vars_array_size;
void** extension_session_vars_array;
} knl_session_attr_common;
set_extension_index
函数,内核侧会调用该函数来设置下标。示例如下。static uint32 dblink_index;
void set_extension_index(uint32 index) {
dblink_index = index;
}
#include "commands/extension.h"
typedef struct dblink_session_context {
remoteConn* pconn;
HTAB* remoteConnHash;
} dblink_session_context;
void init_session_vars(void)
{
RepallocSessionVarsArrayIfNecessary();
dblink_session_context* psc = (dblink_session_context*)MemoryContextAllocZero(u_sess->self_mem_cxt, sizeof(dblink_session_context));
u_sess->attr.attr_common.extension_session_vars_array[dblink_index] = psc;
psc->pconn = NULL;
psc->remoteConnHash = NULL;
}
dblink_session_context* get_session_context()
{
if (u_sess->attr.attr_common.extension_session_vars_array[dblink_index] == NULL) {
init_session_vars();
}
return (dblink_session_context*)u_sess->attr.attr_common.extension_session_vars_array[dblink_index];
}
void example()
{
remoteConn* pconn = get_session_context()->pconn;
}
具体方案实现可见社区PR(https://gitee.com/opengauss/openGauss-server/pulls/1101),插件整改可参考其中对dblink的整改。
除了上述修改点,还存在很多一些较为细节的地方,其中包括有C和C++的差异,例如在C++中new关键字不能作标识符等;大多数还是openGauss和PostgreSQL内核上的差异,下文会对这些差异作详细说明。此外,有些插件可能是基于PG内核新特性开发的,openGauss并不支持,可以考虑将特性整合到插件,必要时修改内核。
下面列举openGauss和PostgreSQL(REL_13_STABLE)内核上的差异,第2章中提到该部分需要不断更新完善,目前仅列出极少部分。
序号 | API_01 |
---|---|
PostgreSQL | void table_close(Relation relation, LOCKMODE lockmode); |
openGauss | #define heap_close(r,l) relation_close(r,l) void relation_close(Relation relation, LOCKMODE lockmode); |
作用 | close any relation |
差异 | 名称不同 |
序号 | API_02 |
---|---|
PostgreSQL | Relation table_open(Oid relationId, LOCKMODE lockmode) |
openGauss | Relation heap_open(Oid relationId, LOCKMODE lockmode, int2 bucketid=-1); |
作用 | open a heap relation by relation OID |
差异 | 名称不同;openGauss的heap_open增加了一个可选参数bucketid |
序号 |
SYSTAB_01 |
---|---|
系统表 | pg_class |
差异 | openGauss新增字段:reltoastidxid, reldeltarelid, reldeltaidx, relcudescrelid, relcudescidx, relhasoids, relhaspkey, relcmprs, relhasclusterkey, relrowmovement, parttype, relfrozenxid64, relbucket, relbucketkey PostgreSQL 新增字段:relrowsecurity, relforcerowsecurity, relispopulated, relispartition, relrewrite , relminmxid , relpartbound relkind 字段可选值差异:PostgreSQL中用p和I表示分区表和分区索引,openGauss用字段parttype表示。 |
备注 | 具体描述可见《开发者指南》-系统表和系统视图-系统表-PG_CLASS |
序号 | SYSVIEW_01 |
---|---|
系统表 | pg_tables |
差异 | openGauss新增字段:tablecreator, created, last_ddl_time PostgreSQL 新增字段:rowsecurity |
备注 | 具体描述可见《开发者指南》-系统表和系统视图-系统视图-PG_TABLES |
PostgreSQL | openGauss | 作用域 |
---|---|---|
error_context_stack | t_thrd.log_cxt.error_context_stack | Thread |
WalSndCaughtUp | t_thrd.walsender_cxt.walSndCaughtUp | Thread |
disable_cost | g_instance.cost_cxt.disable_cost | Instance |
cpu_tuple_cost | u_sess->attr.attr_sql.cpu_tuple_cost | cpu_tuple_cost |
解决方法:参考4.2,在Makefile中添加下面一句。
override CPPFLAGS :=$(filter-out -fPIE, $(CPPFLAGS)) -fPIC
解决方法:参考5类型转换
解决方法:参考6函数声明。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。