将PostgreSQL插件移植到openGauss指导

1 概述

PostgreSQL 社区提供了丰富的插件,但由于 openGauss 和 PostgreSQL 存在一定的差异,如线程/进程模型、系统表和视图等,无法直接为 openGauss 所用,不可避免的需要在插件上做整改。

本文档主要对 Postgresql 插件移植到 openGauss 的过程提供指导说明,旨在让开发人员对 PG 插件所需要的修改有一个具体的了解,基于该文档,可基本实现 PG 插件移植到 openGauss。

2 约束

由于 openGauss 与 PostgreSQL 在内核上存在不少差异,这篇文档未能覆盖所有这些差异,因此仅依赖该文档有可能无法实现 PG 插件的完全迁移,部分差异需要开发者深入内核源码识别,然后可将识别出来的差异补充到该博客的第 9 章对应小节的表格中(博客对应的 gitee 地址:将 PostgreSQL 插件移植到 openGauss 指导,具体操作可见 blog 仓库的README.md),有任何问题可在博客下方留言讨论。

3 移植步骤

  1. 将 PG 插件的代码拷贝到 openGauss 源码的 contrib 目录下

  2. 配置环境变量,需要将数据库的 bin 和 lib 加在操作系统的环境变量 PATH 和 LD_LIBRARY_PATH 中

  3. 到插件目录下,执行make && make install,编译安装插件。

  4. 编译成功后,到数据库中执行create extension extension_name即可使用。

通常步骤 3 和 4 不会直接成功,需要一些必须的修改。下面分类别说明移植 PG 插件所需要做的修改。

4 Makefile 文件

  1. 当前有两种方式支持插件编译,一种是依赖源码编译,一种是用 pgxs 的方式编译,支持插件在一个已经安装的数据库服务上进行编译。建议选择前者的方式,如果采用后者,需要定义 USE_PGXS,但是可能出现部分头文件找不到的问题,这时候需要到源码拷贝头文件到目标目录。
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
  1. -fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code)。使用-fPIC,可以使得动态库可以被多个程序共享。不加 fPIC 加载的 so,要在加载时根据加载到的位置再次重定位。
override CPPFLAGS :=$(filter-out -fPIE,  $(CPPFLAGS)) -fPIC

5 类型转换

  1. ANSI C 规定,void 指针可以复制给其他任意类型的指针,其他任意类型的指针也可以复制给 void 指针,他们之间复制不需要强制类型转换。但是 c++不支持,需要做强制类型转换。
buffer = palloc(MAX_LINESIZE);  ->  buffer = (char*)palloc(MAX_LINESIZE);
  1. 部分 c++编译器不支持 const char*到 char*的隐式转换,需要做强制类型转换。

6 函数声明

  1. C 语言中并没有重载和类这些特性,编译出的符号与 C++不同,例如 print(int i),不会被编译为_print_int,而是直接编译为_print 等。因此如果直接在 C++中调用 C 的函数会失败,例如调用 print(3),c++中实际上会去找_print_int(3),这样就会找不到。加上 extern “C”,指示编译器这部分代码按 C 语言来进行编译,而不是 C++。
extern PGDLLEXPORT Datum  orafce_to_char_timestamp(PG_FUNCTION_ARGS);  ->
extern  "C" PGDLLEXPORT Datum  orafce_to_char_timestamp(PG_FUNCTION_ARGS);

可以通过 nm -D so 文件查看生成的符号。

7 安全函数整改

  1. 推荐使用安全函数(可见 securec.h),并对安全函数的返回值作检查,openGauss 定义了几个常用的检查宏,如下。
#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\()

8 变量转换

  1. 对比 PostgreSQL,openGauss 收集了原有的全局变量,将其收集在了 g_instance、t_thrd、u_sess(分别是全局变量、线程变量和会话变量)等结构体内,因此需要作相应替换(通过编译报错体现,需要到内核代码层面查看变量具体存放位置)。插件的全局变量可通过 nm -D so | grep ‘B’排查。(具体见 7.7)
econtext = error_context_stack;  ->  econtext = t_thrd.log_cxt.error_context_stack;
  1. PG 采用进程模型,用户会话进来时会创建一个独立的进程去处理,此时插件定义的全局变量在该进程内就是唯一的会话变量。而 openGauss 采用线程模型,所有会话共享同一份全局变量,因此需要将全局变量修改为会话变量。对于只读的全局变量,保持原样即可,而对于多次修改的变量,需要作如下修改。

a. 如果不考虑在线程池模式下使用插件,将全局变量修改为 THR_LOCAL 变量,即线程变量,因为用户会话进来会创建一个独立的线程。

b. 如果需要线程池,就需要作额外的修改。线程池模式下,一个用户会话可能会切换多个线程,单纯的将全局变量改为线程变量,在切换线程时会丢失对该变量的修改。openGauss 提供了插件自定义会话变量的方式,具体实现如下。(以 dblink 为例)

  1. 内核侧在 u_sess 中定义一个指针数组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;
  1. 插件侧需定义一个全局的下标变量,用于获取数组元素,并且提供set_extension_index函数,内核侧会调用该函数来设置下标。示例如下。
static uint32 dblink_index;
void set_extension_index(uint32 index) {dblink_index = index;
}
  1. 此外,插件侧还需要定义步骤 1 提到的会话变量结构体,存放该插件自身所有的会话变量,以及提供函数 init_session_vars,主要是初始化该结构体,并把指针存放在数组的对应下标位置。示例如下。
#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;
}
  1. 最终,在插件使用会话变量时,根据下标到数组中获取对应的结构体指针即可。
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的整改。

9 其他

除了上述修改点,还存在很多一些较为细节的地方,其中包括有 C 和 C++的差异,例如在 C++中 new 关键字不能作标识符等;大多数还是 openGauss 和 PostgreSQL 内核上的差异,下文会对这些差异作详细说明。此外,有些插件可能是基于 PG 内核新特性开发的,openGauss 并不支持,可以考虑将特性整合到插件,必要时修改内核。

下面列举 openGauss 和 PostgreSQL(REL_13_STABLE)内核上的差异,第 2 章中提到该部分需要不断更新完善,目前仅列出极少部分。

9.1 API

序号API_01
PostgreSQLvoid 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
PostgreSQLRelation table_open(Oid relationId, LOCKMODE lockmode)
openGaussRelation heap_open(Oid relationId, LOCKMODE lockmode, int2 bucketid=-1);
作用open a heap relation by relation OID
差异名称不同;openGauss 的 heap_open 增加了一个可选参数 bucketid

9.2 系统表

<div style="width: 150pt">序号</div>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 |

9.3 系统视图

序号SYSVIEW_01
系统表pg_tables
差异openGauss 新增字段:tablecreator, created, last_ddl_time PostgreSQL 新增字段:rowsecurity
备注具体描述可见《开发者指南》-系统表和系统视图-系统视图-PG_TABLES

9.4 系统函数

9.5 LOCK

9.6 Memory Context

9.7 全局变量

PostgreSQLopenGauss作用域
error_context_stackt_thrd.log_cxt.error_context_stackThread
WalSndCaughtUpt_thrd.walsender_cxt.walSndCaughtUpThread
disable_costg_instance.cost_cxt.disable_costInstance
cpu_tuple_costu_sess->attr.attr_sql.cpu_tuple_costcpu_tuple_cost

10 常见错误信息

  1. 编译安装时报错:dangerous relocation: unsupported relocation

解决方法:参考 4.2,在 Makefile 中添加下面一句。

override CPPFLAGS :=$(filter-out -fPIE, $(CPPFLAGS)) -fPIC

  1. 编译安装时报错:error: invalid conversion from ‘void’ to ‘char’ [-fpermissive]

解决方法:参考 5 类型转换

  1. create extension 时报错:could not find function “xxx” in file “xxx.so”

解决方法:参考 6 函数声明。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/746441.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试官:说说C++的引用和指针有什么区别

C中的引用和指针虽然都是用于间接访问和操作对象的工具&#xff0c;但它们之间存在几个重要的区别&#xff1a; 本质和存在性&#xff1a; 指针是一个变量&#xff0c;它存储了另一个变量的地址。指针有自己的内存地址&#xff0c;并且可以改变其指向的内容。 引用是一个别名&a…

springboot271制造装备物联及生产管理ERP系统

制造装备物联及生产管理ERP系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装制造装备物联及…

3月14日,每日信息差

&#x1f396; 素材来源官方媒体/网络新闻 &#x1f384; 5.5G通信网络在海南投入商用&#xff0c;较5G提升10倍 &#x1f30d; 国务院批复同意&#xff0c;珠海港口岸将整合并扩大开放 &#x1f30b; 同有科技&#xff1a;正在研究新型磁电存储技术 &#x1f381; 美国折扣零售…

考研模拟面试-答案【攻略】

考研模拟面试-答案【攻略】 前言版权推荐考研模拟面试-答案前面的问题通用问题专业题数据结构计算机网络操作系统数据库网络安全 手写题数据结构操作系统计算机网络 代码题基础代码题其他代码题 后面的问题补充题目 基础代码题答案链栈循环队列1循环队列2哈希表 最后 前言 202…

Oracle基础-分组查询 备份

一、概述 数据分组的目的是用来汇总数据或为整个分组显示单行的汇总信息&#xff0c;通常在查询结果集中使用GROUP BY 子句对记录进行分组。在SELECT 语句中&#xff0c;GROUP BY 子句位于FROM 子句之后&#xff0c;语法格式&#xff1a; SELECT columns_list FROM table_nam…

【测试知识】业务面试问答突击版1

高内聚低耦合 高内聚指的是将相关的功能或数据组织在一起&#xff0c;使得模块内部的各个元素紧密地联系在一起&#xff0c;完成特定的任务。 低耦合指的是模块之间的依赖关系尽可能地降低&#xff0c;模块之间的接口简单清晰&#xff0c;减少模块之间的相互影响。 文章目录 整…

【数据结构】二叉搜索树底层刨析

文章目录 1. 二叉搜索树的实现2. 二叉搜索树的应用3. 改造二叉搜索树为 KV 结构4. 二叉搜索树的性能分析 1. 二叉搜索树的实现 namespace key {template<class K>struct BSTreeNode{typedef BSTreeNode<K> Node;Node* _left;Node* _right;K _key;BSTreeNode(const…

工作中用到的 —— 工作总结提炼出来的股文

这里是目录 ---------------- VUE相关 -----------------1 - Vue3 是怎么得更快的&#xff1f;1-1 Fragment [frɡˈment]1-2 Suspense [səˈspens]1-3 Teleport [ˈtelipɔːt]1-4 v-memo 2- 说一下 Composition API3- 说一下 setup4- watch 和 watchEffect 的区别5- Vue3 响…

Sublime查看ANSI编码文档乱码问题

原因为没有安装对应的解码插件。 选择安装插件包 选择插件包&#xff1a;ConvertToUTF8或者GBK&#xff0c;我试了第一个插件包不行&#xff0c;安装GBK插件包后OK。

Git如何清除账户凭证

场景&#xff1a;一般发生在Git用户变更的情况 1.git base 操作 Git会使用凭证助手 credential.helper来储存账户凭证&#xff0c;通过以下命令移除&#xff1a; git config --system --unset credential.helper 除了system系统级外&#xff0c;还有 global、local范围。 查…

20万英文单词同义词宝典ACCESS\EXCEL数据库

英语同义词反义词的数据之前搞到过《近万英语单词同义词典ACCESS数据库》、《上百万英语同义反义词词典ACCESS数据库》&#xff0c;今天又搞到一份几十万行数据的&#xff0c;发上来看看有没有适合朋友们的需求。 今天这个数据提供了非常全的词汇单词以及词汇对应的含义以及近…

将Java项目Jar包制作成Docker镜像

文章目录 前言一、准备事项二、使用步骤1.Dockerfile脚本2.制作镜像推送Harbor仓库前言 以前单体项目通常采用传统部署方式将项目打成Jar包再进行部署。如果我们项目是微服务则需要进行Docker容器部署。本文将介绍如何在本地将Jar包制作成Docker镜像并推送到Harbor仓库 一、准…

Spring揭秘:ClassPathScanningProvider接口应用场景及实现原理!

技术应用场景 ClassPathScanningCandidateComponentProvider是Spring框架中一个非常核心的类&#xff0c;它主要用于在类路径下扫描并发现带有特定注解的组件&#xff0c;支持诸如ComponentScan、Component、Service、Repository和Controller等注解的自动扫描和注册。 ClassP…

Mysql 无法启动,mysql-bin.日志丢失删除处理

在linux操作系统中&#xff0c;当mysql无法启动时候&#xff0c;先看日志 2024-03-15T05:20:16.352075Z 0 [Warning] [MY-000081] [Server] option max_allowed_packet: unsigned value 107374182400 adjusted to 1073741824. 2024-03-15T05:20:16.352156Z 0 [Warning] [MY-010…

Marshmallow,一个有点甜的Python库

前言 在许多场景中&#xff0c;我们常常需要执行Python对象的序列化、反序列化操作。例如&#xff0c;在开发REST API时&#xff0c;或者在进行一些面向对象化的数据加载和保存时&#xff0c;这一功能经常派上用场。 经常cv Python代码的臭宝&#xff0c;接触最多的应该是通过…

验证与分享执行计划突变引发的问题

作者简介 张瑞远&#xff0c;曾经从事银行、证券数仓设计、开发、优化类工作&#xff0c;现主要从事电信级IT系统及数据库的规划设计、架构设计、运维实施、运维服务、故障处理、性能优化等工作。 持有Orale OCM,MySQL OCP及国产代表数据库认证。 获得的专业技能与认证包括 Oce…

被军训到的两天

1.gradle7.6.1 1.安装gradle7.6.1,一定要注意的是&#xff0c;使用的JDK是否能用&#xff0c;比如gradle7.6.1用的是JDK11。 2. F:/sofer....是Gradle自己的仓库地址&#xff0c;注意不能和maven使用一样的仓库。 使用specified location,可以避免下本项目的gradle版本&…

如何更改SonarQube的JDK版本

如何更改SonarQube的JDK版本 当需要升级或更换SonarQube所使用的JDK版本时&#xff0c;可以按照以下步骤进行操作&#xff1a; 第一步&#xff1a;确定新JDK的安装路径 首先&#xff0c;您需要找到您打算使用的JDK的安装路径。这通常是一个包含JDK各种工具和库的文件夹。请确…

ego - 人工智能原生 3D 模拟引擎——基于AI的3D引擎,可以做游戏、空间计算、元宇宙等项目

1. 产品概述:Ego是一款AI本地化的3D模拟引擎,旨在让非技术创作者通过自然语言生成逼真的角色、3D世界和交互式脚本。该平台提供了创建和分享游戏、虚拟世界和交互体验的功能。 2. 定位:Ego定位于解决开放世界游戏和模拟的三大难题:难以编写游戏脚本、非玩家角色无法展现人…

性能测试-Redis

一、测试注意点 1、缓存预热 如果程序初次运行&#xff0c;此时由于数据尚未加载到缓存&#xff0c;则程序的响应时间会明显变长 注意事项&#xff1a; 性能测试的时候 出现 非常不稳定的现象程序刚启动&#xff0c;它的性能 明显 低于 已经运行一段时间的 1.1 测试缓存没…