如何写一个 PostgreSQL Extension
什么是 PostgreSQL Extension
PostgreSQL Extension 是一个可插拔的功能扩展,用于在 PostgreSQL 数据库系统中添加额外的功能和能力。这些扩展可以由第三方开发者开发并加入到 PostgreSQL 中,以满足特定的需求。扩展可以增强数据库功能。 有些非常不错的 Extensions 甚至成了一些公司选型 Postgres 的理由比如:TimescaleDB, PostGIS 等等。
今年开始异常火爆的向量数据库,因为有 pgvector 也让 pg 有了向量计算和存储的能力。
本文会介绍如何编写 extensions 和推荐一些编写 Extensions 的资源。
如何写一个 Extensions
传统的 Extensions 开发一般情况下我们会 c 语言,引入 Postgers.h
写好 Makefile 和 SQL 开发,现在也有了用 Rust 编写 Extensions 的能力 -> pgrx 借助 pgrx 我们能更好的专注 extensions 中算法本身,也可以借助 Rust 强大的生态更容易的编写 extensions 需要的逻辑,进行更快速,更安全的开发。
以下分别介绍 C 和 Rust 两种开发方式。
C 语言开发 Extensions
以 hello_world 为例,需要在 hello_world 文件夹中建下面 4 个文件
hello.control # 插件名.control
hello.c # 插件名.c
hello--1.0.sql # 插件名--1.0.sql
Makefile # 用于编译
cat hello.control
comment = 'hello:'
default_version = '1.0'
module_pathname = '$libdir/hello'
relocatable = false
superuser = true
剩下的可以参考这个 pg 的 hello_world 项目 https://github.com/magnusp/pg_hello
cat pg_hello.c
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
Datum hello( PG_FUNCTION_ARGS );
PG_FUNCTION_INFO_V1( hello );
Datum
hello( PG_FUNCTION_ARGS )
{
// variable declarations
char greet[] = "Hello, ";
text *towhom;
int greetlen;
int towhomlen;
text *greeting;
// Get arguments. If we declare our function as STRICT, then
// this check is superfluous.
if( PG_ARGISNULL(0) ) {
PG_RETURN_NULL();
}
towhom = PG_GETARG_TEXT_P(0);
// Calculate string sizes.
greetlen = strlen(greet);
towhomlen = VARSIZE(towhom) - VARHDRSZ;
// Allocate memory and set data structure size.
greeting = (text *)palloc( greetlen + towhomlen );
SET_VARSIZE(greeting, greetlen + towhomlen + VARHDRSZ);
// Construct greeting string.
strncpy( VARDATA(greeting), greet, greetlen );
strncpy( VARDATA(greeting) + greetlen,
VARDATA(towhom),
towhomlen );
PG_RETURN_TEXT_P( greeting );
}
代码的一些解释:
#include "postgres.h"
包含了大部分编写 postgres 相关程序需要的东西,每个 extensions 必须包含这个#include "fmgr.h"
则包含了PG_GETARG_XXX、PG_RETURN_XXX和PG_ARGISNULL 等编写 extensions 必要的宏- Datum 是 data 的单数是在 pg 中最重要的数据类型之一,它肩负着在PG 内核与用户代码之间传递数据的责任
- PG_MODULE_MAGIC 这个宏是编写 extensions 的一个必要的宏为了后面编译生成的库才可以被 postgresql 加载
在这之后就可以编写好 Makefile 把 pg 的 PATH 加入到环境变量中之后 make && make install
在这之后进入到 psql, create extension hello; select hello('hello'); 就可以了
当然后续可以写一些测试,需要建一个文件夹名为 sql 把相关的测试写在里面,再建一个文件夹名为 expected 把测试跑出的结果写在里面,在 Makefile 加上这句 REGRESS = hello
, 就可以利用 pg 的 installcheck 了
cat sql/hello.sql
CREATE EXTENSION hello;
select hello_hello();
**如果不知道如何写插件可以参考 pg 核心开发者这个项目,里面有各种各样的 extensions **
- pg_plugins
- 参考文章1 - Postgresql 编写自定义 C 函数
- 参看文章2 - PostgreSQL插件开发
- 可以参考迟先生 @skyzh 的有趣项目 pg_poop
Rust 语言开发 Extensions
当然现在是 2023 年我们完全可以借助 Rust 来开发 Extensions, 这特别得益于 pgrx 这个项目它的前身也是一个非常棒的 pg 插件 zombodb
来看看借助 pgrx 开发的优秀的 pg 插件
- pgvecto.rs -> pgvector 的 Rust 版
- postgresml -> postgres ml 第二版用 Rust 重写,速度大幅提升
- plrust -> 在 pg 中使用 Rust 作为 Procedural Language
编写起来就比 C 简单多了,只需要
- 安装 pgrx
- cargo pgrx init
- cargo pgrx new hello
- cargo pgrx install or cargo prgx run
一个简单的 hello 程序就做好了,其中 cargo pgrx new hello
帮助我们生成了所有需要的文件,其中 pgrx-examples 文件夹中包含了很多如何使用 pgrx 编写的例子。
当然大家可以参考这个项目 pg_slugify,利用了 Rust 的生态,几行代码做了一个非常有用 extension, 大家的很多简单的脚本完全可以利用 Rust 编写成插件方便自己开发。
推荐一些资源
- pgxn extensions 托管
- 1000+ PostgreSQL EXTENSIONs
- postgres extensions 入门培训
补充
2024.11.07 我用 pgrx 写了两个 extensions https://github.com/yihong0618/pg_polyline https://github.com/yihong0618/pg_geohash