openGauss 系统函数添加指导

openGauss 系统函数添加指导

1、函数架构简介

openGauss 内函数的可以分为两个部分:

  • ​ 身份注册声明:openGauss 中存在一个系统表 pg_proc,这个表存放了所有函数的基本元信息,相当于函数的“户口本”,只有在其中可以查到的函数,才可以在 SQL 语句中进行调用,才有“数据库函数”的身份。常见的注册方式有:builtin、升级脚本、CREATE FUNCTION 语句、EXTENSION。
  • ​ 底层功能实现:实现其功能的具体逻辑代码,可以根据其所用的语言分为四类:INTERNAL, SQL, PLPGSQL、C。

四中常见的函数注册创建方式,分别对应着着不同的场景:

  • builtin:源代码中存在一个名为 builtin_funcs.ini 的文件,存放着一系列内置函数的元信息,在初始化安装数据库时,会通过某些方式,全量扫描此文件,将里面罗列的函数批量注册到 pg_proc 系统表。
  • 升级脚本:数据库由老版本升级到新版本的场景下,不会也不能遍历重刷 builtin_funcs.ini 到 pg_proc,因此若新版本有新增函数,就需要编写一个升级脚本,在升级过程中通过升级脚本将新增函数注册到 pg_proc 之中。
  • CREATE FUNCTION: 通过CREATE FUNCTION ... BEGIN ... END语句,一把完成注册和实现。
  • EXTENSION:随着 extension 进行注册和加载。

四类语言实现方案分别有不同的注册声明方式以及实现特征:

  • INTERNAL: 通过 builtin 或升级脚本进行注册,底层功能通过 C 语言实现的函数,也是数据库最常见的内置函数,如 pg_sleep()。其底层功能函数函数名可以再 pg_proc 的 prosrc 列查到。
  • SQL: 通过 builtin 或者升级脚本进行注册,底层功能通过一句 SQL 实现的函数,也是数据库内置函数的一种。如 to_char() ,在数据库底层会转换为一句select CAST(... AS VARCHAR2);,这一句在 pg_proc 的 prosrc 列可以查到,通常是为了复用已有功能模块来适配新接口而采用这种实现方案。
  • PLPGSQL: 这个就是我们所熟知的,使用 plpgsql 进行编写创建的函数了,通过语句一次完成声明与实现。pg_proc 的 prosrc 列存放了这个语句的源代码。
  • C: 出现在各种 extension 之中,内部功能使用 C 语言实现。这个和 INTERNAL 比较类似,区别在于其具体注册方式为通过 extension 进行注册,并且底层代码是在外部 lib 之中,而 INTERNAL 是在 gaussdb 二进制内的。可以在 pg_proc 的 prosrc、probin 列查到其 lib 路径以及函数符号信息。

其中 INTERNAL、SQL 类的函数,因为都可以通过 builtin 的方式整,因此也都常被统称为 builtin 函数。

一个普通函数调用流程大致为:

1、解析 SQL 语句,获取到函数名以及参数值与类型等信息。

2、根据以上信息,在 pg_proc 中检索到这个函数的元数据,元数据中包含默认值、实现语言、底层函数、估算代价等所有信息。

3、根据其实现语言,调用其具体底层接口模块。如:INTERNAL 类型会直接调用其元数据中的底层 C 语言代码函数;C 类型会根据元数据信息加载相关 lib 后调用 lib 中的 C 语言代码函数;SQL 类型会直接转而执行元数据 prosrc 中存放的 sql 语句;PLPGSQL 类型会转而走过程语言模块解释执行 prosrc 中存放的源代码。

另外还有一种稍微特殊的函数——聚集函数,它其实是在普通函数的架构基础上做的功能变更与扩展,其架构和添加流程与普通函数有些差异。我们分两章介绍如何添加普通的 INTERNAL 函数和聚集函数。

2、如何添加一个普通的 INTERNAL 函数

了解了上面的架构与流程后,不难得出,添加一个普通的 INTERNAL 函数,可分为四个步骤:

​ 1、声明函数身份。将我们已经提前设计好的函数的各种属性,如参数数量类型、返回值类型、稳定性等等,按照特定的格式添加进 buitin_funcs.ini 文件之中。

​ 2、实现功能代码。在内核代码合适位置,实现一个 C 语言的函数,来实现对应的功能。

​ 3、关联声明实现。将上一个步骤编写函数的函数名,添加到 builtin_funcs.ini 对应条目的对应位置。

​ 4、编写升级脚本。用于在升级流程之中注册 SQL 函数身份。

2.1 声明函数身份

在这之前我们需要已经提前设计好自己的函数属性以及功能,如参数数量类型、返回值类型、稳定性等等,将这些信息按照特定的格式和顺序填写到./src/common/backend/catalog/builtin_funcs.ini 文件之中。

这个文件中需要按照如下结构进行书写:

AddFuncGroup(
    "pg_sleep", 1,
    AddBuiltinFunc(_0(2626), _1("pg_sleep"), _2(1), _3(true), _4(false), _5(pg_sleep), _6(2278), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1, 701), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_sleep"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL),  _36(0), _37(false))
),

可以看到其有内外两层组成。

外层为AddFuncGroup("pg_sleep", 1, AddBuiltinFunc(...)),其第一个成员变量为函数名,第二个成员变量为重载数量,后面的 AddBuiltinFunc 结构为函数元信息。这个结构会匹配内核代码中的结构体struct FuncGroup需要十分注意的是,这个结构需要按照第一个成员也就是函数名的 ASCII 大小升序,添加到对应的位置

内层AddBuiltinFunc为函数元信息,其目前一共含有 38 个属性,与内核代码结构体struct Builtin_func和系统表 pg_proc 都有对应关系。我们根据如下表每个属性含义,完善 AddBuiltinFunc 结构(可暂不关注属性 5 与 25)。

编号 含义 对应 Builtin_func
0 oid,函数的唯一标识 id,需要小于 10000 且不可以和已有函数重复。 Oid foid;
1 函数名 const char* funcName
2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值