Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何写一个 PostgreSQL Extension #270

Open
yihong0618 opened this issue Jul 8, 2023 · 3 comments
Open

如何写一个 PostgreSQL Extension #270

yihong0618 opened this issue Jul 8, 2023 · 3 comments
Labels
技术文章 技术文章

Comments

@yihong0618
Copy link
Owner

yihong0618 commented Jul 8, 2023

什么是 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 );
}

代码的一些解���:

  1. #include "postgres.h" 包含了大部分编写 postgres 相关程序需要的东西,每个 extensions 必须包含这个
  2. #include "fmgr.h" 则包含了PG_GETARG_XXX、PG_RETURN_XXX和PG_ARGISNULL 等编写 extensions 必要的宏
  3. Datum 是 data 的单数是在 pg 中最重要的数据类型之一,它肩负着在PG 内核与用户代码之间传递数据的责任
  4. 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 **

Rust 语言开发 Extensions

当然现在是 2023 年我们完全可以借助 Rust 来开发 Extensions, 这特别得益于 pgrx 这个项目它的前身也是一个非常棒的 pg 插件 zombodb

来看看借助 pgrx 开发的优秀的 pg 插件

  • pgvecto.rs -> pgvector 的 Rust 版
  • postgresml -> postgres ml 第二版用 Rust 重写,速度大幅提升
  • plrust -> 在 pg 中使用 Rust 作为 Procedural Language

编写起来就比 C 简单多了,只需要

  1. 安装 pgrx
  2. cargo pgrx init
  3. cargo pgrx new hello
  4. cargo pgrx install or cargo prgx run

一个简单的 hello 程序就做好了,其中 cargo pgrx new hello 帮助我们生成了所有需要的文件,其中 pgrx-examples 文件夹中包含了很多如何使用 pgrx 编写的例子。

当然大家可以参考这个项目 pg_slugify,利用了 Rust 的生态,几行代码做了一个非常有用 extension, 大家的很多简单的脚本完全可以利用 Rust 编写成插件方便自己开发。

推荐一些资源

@yihong0618 yihong0618 added the 技术文章 技术文章 label Jul 8, 2023
@wey-gu
Copy link
Sponsor

wey-gu commented Jul 28, 2023

真棒👍🏻

@tao12345666333
Copy link

这样看的话,用 Rust 写扩展是更简单 & 推荐的方式?

@yihong0618
Copy link
Owner Author

这样看的话,用 Rust 写扩展是更简单 & 推荐的方式?

对于熟悉 Rust 不太了解 pg 插件开发的朋友,是。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
技术文章 技术文章
3 participants