#postgresql #extension

pgrx

pgrx:一个用于创建Postgres扩展的Rust框架

38个版本

新版本 0.12.1 2024年8月21日
0.12.0-beta.32024年7月16日
0.12.0-alpha.12024年3月1日
0.11.2 2023年12月5日
0.10.0-beta.12023年7月14日

数据库接口中排名第15

Download history 2593/week @ 2024-05-02 3343/week @ 2024-05-09 5148/week @ 2024-05-16 4240/week @ 2024-05-23 3707/week @ 2024-05-30 4307/week @ 2024-06-06 3505/week @ 2024-06-13 4073/week @ 2024-06-20 4335/week @ 2024-06-27 4054/week @ 2024-07-04 3125/week @ 2024-07-11 5451/week @ 2024-07-18 4766/week @ 2024-07-25 4054/week @ 2024-08-01 4810/week @ 2024-08-08 2592/week @ 2024-08-15

每月下载量18,177
用于 8 crates

MIT许可证

14MB
367K SLoC

Logo

pgrx

用Rust构建Postgres扩展!

GitHub Actions badge crates.io badge docs.rs badge Twitter Follow Discord Chat

pgrx是一个用于在Rust中开发PostgreSQL扩展的框架,力求尽可能符合Rust的惯用性和安全性。

pgrx支持Postgres 12至Postgres 17。

欢迎加入我们的Discord服务器

主要功能

  • 一个带有cargo-pgrx的完全托管开发环境
    • cargo pgrx new:快速创建新的扩展
    • cargo pgrx init:安装新的(或注册现有的)PostgreSQL安装
    • cargo pgrx run:运行您的扩展并在psql(或pgcli)中交互式测试它
    • cargo pgrx test:对您的扩展进行单元测试,跨多个PostgreSQL版本
    • cargo pgrx package:为您的扩展创建安装包
    • 更多内容请参阅README.md
  • 针对多个Postgres版本
    • 从相同的代码库支持Postgres 12至Postgres 16
    • 使用Rust功能门控来使用特定版本的API
    • 无缝测试所有版本
  • 自动模式生成
  • 安全第一
    • 将 Rust 的 panic! 转换为 Postgres 的 ERROR,终止事务而不是进程
    • 内存管理遵循 Rust 的 drop 语义,即使在 panic!elog(ERROR) 的情况下也是如此
    • #[pg_guard] 过程宏确保上述功能
    • Postgres DatumOption<T> where T: FromDatum
      • NULL Datum 被安全地表示为 Option::<T>::None
  • 支持一等 UDF
    • 使用 #[pg_extern] 注释函数以将它们暴露给 Postgres
    • 对于 RETURNS SETOF,返回 pgrx::iter::SetOfIterator<'a, T>
    • 对于 RETURNS TABLE (...),返回 pgrx::iter::TableIterator<'a, T>
    • 使用 #[pg_trigger] 创建触发函数
  • 易于定制的类型
    • 使用 #[derive(PostgresType)] 将 Rust 结构体用作 Postgres 类型
      • 默认情况下,在内存/磁盘上表示为 CBOR 编码的对象,并以 JSON 格式表示为可读的
      • 提供自定义的内存/磁盘/可读表示
    • 使用 #[derive(PostgresEnum)] 将 Rust 枚举用作 Postgres 枚举
    • 支持使用 pgrx::composite_type!("Sample") 宏支持复合类型
  • 服务器编程接口 (SPI)
    • 安全访问 SPI
    • 从 SPI 上下文中透明地返回所有权的 Datum
  • 高级功能
    • 通过 pgrx::PgMemoryContexts 安全访问 Postgres 的 MemoryContext 系统
    • Executor/planner/transaction/subtransaction 钩子
    • 安全使用Postgres提供的指针与pgrx::PgBox<T>(类似于alloc::boxed::Box<T>
    • #[pg_guard]宏用于保护需要传递给Postgres的Rust函数extern "C"
    • 通过类似于eprintln!的宏访问Postgres的日志系统
    • 通过pgrx::pg_sys模块直接访问Postgres内部大部分的unsafe区域
    • 定期添加新功能!

系统要求

PGRX已在x86_64和aarch64 Linux以及aarch64 macOS目标上进行测试,以确保其工作。目前预计它可以在其他“Unix”操作系统上运行,可能需要一些小的更改,但这些尚未经过测试。到目前为止,PGRX的一些构建工具在Windows上运行,但并非全部。

  • 一个Rust工具链:rustccargorustfmt。获取这些的推荐方法是来自https://rustup.rs
  • git
  • libclang 11或更高版本(用于bindgen)
    • 类似Debian的系统:apt install libclang-devapt install clang
    • 类似RHEL的系统:yum install clang
  • GCC 7或更高版本
  • PostgreSQL的构建依赖项
    • 类似Debian的系统:sudo apt-get install build-essential libreadline-dev zlib1g-dev flex bison libxml2-dev libxslt-dev libssl-dev libxml2-utils xsltproc ccache pkg-config
    • 类似RHEL的系统:sudo yum install -y bison-devel readline-devel zlib-devel openssl-devel wget ccache && sudo yum groupinstall -y 'Development Tools'

† PGRX没有MSRV策略,因此可能需要Rust的最新稳定版本,可通过Rustup获取

† 不需要本地PostgreSQL服务器安装。使用cargo pgrx可以自行下载和编译PostgreSQL版本。

⹋ PGRX尚未测试在32位上工作:库假设有一个8字节的pg_sys::Datum,这可能导致在32位上的意外行为,例如从int8double中丢弃4个字节的数据。这本身可能不是“不安全的”,因为它只是不合理的,但它可能会破坏PGRX扩展的合理安全假设。我们不打算在没有相当的技术和财务贡献的情况下添加支持。

如何: macOS上的Homebrew

由于macOS没有提供包管理器,建议使用https://brew.sh.cn来处理C依赖项。

特别是,如果您还没有这些,可能需要这些:

brew install git icu4c pkg-config

入门指南

首先,安装系统依赖项

现在安装cargo-pgrx子命令。

cargo install --locked cargo-pgrx

cargo-pgrx准备就绪后,您可以初始化“PGRX Home”目录。

cargo pgrx init

init命令下载所有当前支持的PostgreSQL版本,将它们编译到${PGRX_HOME},并运行initdb

您还可以使用现有的(用户可写的)PostgreSQL安装,或安装版本的一个子集,请参阅README.mdcargo-pgrx部分以获取详细信息

现在您可以从特定的pgrx扩展开始工作。

cargo pgrx new my_extension
cd my_extension

这将为扩展crate创建一个新的目录。

$ tree 
.
├── Cargo.toml
├── my_extension.control
├── sql
└── src
    └── lib.rs

2 directories, 3 files

新扩展包含一个示例,因此您可以立即运行它。

cargo pgrx run

这会将扩展编译成共享库,将其复制到指定的Postgres安装中,启动该Postgres实例,并将其连接到与扩展同名的数据库。

一旦cargo-pgrx将我们带到psql,我们就可以加载扩展并对示例函数执行SELECT操作。

my_extension=# CREATE EXTENSION my_extension;
CREATE EXTENSION

my_extension=# SELECT hello_my_extension();
 hello_my_extension
---------------------
 Hello, my_extension
(1 row)

有关如何管理pgrx扩展的更多详细信息,请参阅管理pgrx扩展

升级

随着新版本的Postgres被pgrx支持,您可以重新运行pgrx init过程以下载和编译它们。

cargo pgrx init

Postgres类型到Rust的映射

Postgres类型 Rust类型(作为Option<T>
bytea Vec<u8>&[u8](零拷贝)
text String&str(零拷贝)
varchar String&str(零拷贝)或char
"char" i8
smallint i16
integer i32
bigint i64
oid u32
real f32
double precision f64
bool bool
json pgrx::Json(serde_json::Value)
jsonb pgrx::JsonB(serde_json::Value)
date pgrx::Date
time pgrx::Time
timestamp pgrx::Timestamp
带时区的时间 pgrx::TimeWithTimeZone
带时区的timestamp pgrx::TimestampWithTimeZone
anyarray pgrx::AnyArray
anyelement pgrx::AnyElement
box pgrx::pg_sys::BOX
point pgrx::pg_sys::Point
tid pgrx::pg_sys::ItemPointerData
cstring &core::ffi::CStr
inet pgrx::Inet(String) -- TODO: needs better support
numeric pgrx::Numeric<P, S>orpgrx::AnyNumeric
void ()
ARRAY[]::<type> Vec<Option<T>>pgrx::Array<T>(零拷贝)
int4range pgrx::范围<i32>
int8range pgrx::范围<i64>
numrange pgrx::Range<Numeric<P, S>>pgrx::Range<AnyRange>
daterange pgrx::范围<pgrx::Date>
tsrange pgrx::范围<pgrx::Timestamp>
tstzrange pgrx::范围<pgrx::TimestampWithTimeZone>
NULL Option::None
内部 pgrx::PgBox<T> 其中 T 是任何 Rust/Postgres 结构体
uuid pgrx::Uuid([u8; 16])

还存在 IntoDatumFromDatum 特性,用于实现额外的类型转换,以及 #[derive(PostgresType)]#[derive(PostgresEnum)] 以自动转换自定义类型。

请注意,textvarchar 转换为 &strString,因此 PGRX 假设您使用的任何 Postgres 数据库都具有与 UTF-8 兼容的编码。目前,如果 PGRX 检测到这有误,它将引发恐慌,以通知您,程序员,您犯了错误。然而,最好不要依赖这种行为,因为 UTF-8 验证可能是一个性能风险。此问题以前被认为是根本不可能发生的,PGRX 可能会决定在未来更改其执行 UTF-8 验证检查的细节,以减轻性能风险。

默认的 Postgres 服务器编码是 SQL_ASCII,它既不保证 ASCII 也不保证 UTF-8(因为 Postgres 会接受但不忽略非 ASCII 字节)。为了获得最佳效果,始终使用 UTF-8 的 PGRX,并在创建数据库时明确设置数据库编码。

深入了解

注意事项 & 已知问题

可能还有更多,但主要需要注意的是

  • 线程不支持。Postgres 是严格单线程的。因此,如果您冒险使用线程,这些线程 MUST NOT 调用 任何 内部 Postgres 函数,或使用任何 Postgres 提供的指针。还有 Postgres 使用 sigprocmask 的潜在问题。这在 -hackers 列表中正在进行讨论,甚至提供了一个补丁,但对话似乎已经陷入僵局(https://postgresql.ac.cn/message-id/flat/5EF20168.2040508%40anastigmatix.net#4533edb74194d30adfa04a6a2ce635ba)。
  • 如何在 async 上下文中正确与 Postgres 交互尚未探索。
  • pgrx 包裹了许多 不安全 代码,其中一些安全条件定义得不好。即使是从安全代码中,使用 pgrx 也可能诱导出不合理和不受欢迎的行为,其中一些包装器可能从根本上是不正确的。请报告可能出现的任何问题。
  • 并非所有Postgres内部组件都被包含或包装。这并非因为不可能实现,而是因为这是一项极其庞大的任务。如果您发现了所需的Postgres内部API,请提交一个issue,我们将将其暴露出来,至少通过 pgrx::pg_sys 模块。
  • Windows不受支持。虽然可能支持,但需要使用 cargo-pgrx 和解决如何编译 pgrx 的 "cshim" 静态库的工作。
  • ALTER EXTENSION my_extension UPDATE; 之前启动的会话将继续看到 my_extension 的旧版本。新会话将看到扩展的更新版本。
  • pgrx 被许多 "生产中" 使用,但它不是 "1.0.0" 或更高版本,尽管SemVer建议生产级软件使用该版本。这是因为有许多未解决的关于稳定性和易用性的问题,可能需要通过破坏性更改来解决,在某些情况下需要使用最前沿的Rust功能来暴露稳定的接口。虽然计划在某个时候发布1.0.0版本,但似乎明智地等待,直到看起来似乎下周不需要2.0.0版本,并且剩余的问题可以推迟。

待办事项

我们的待办事项列表上还有一些事情

  • 自动扩展架构升级脚本
  • 改进单元测试框架
  • 更好的/更安全的Datum管理API
  • 改进生成的绑定组织
  • 安全地包装更多Postgres内部API
  • 更多示例——特别是在内存管理和各种 derive 宏 #[derive(PostgresType/Enum)]

功能标志

PGRX为不涉及配置Postgres版本的Rust代码提供了可选的功能标志,而是扩展了对其他类型Rust代码的额外支持。这些默认不包含。

"unsafe-postgres":允许编译针对具有不同ABI的Postgres分支

截至Postgres 15,分支可以指定它们使用与规范Postgres不同的ABI。由于pgrx对Postgres内部ABI的假设无数,因此它无法保证编译的pgrx扩展可以在这种Postgres分支中执行。您,尊敬的编译器运行者,可以通过指定 unsafe-postgres 功能标志来保证这一点。否则,pgrx扩展将无法编译,并出现类似以下错误的错误:

error[E0080]: evaluation of constant value failed
   --> pgrx/src/lib.rs:151:5
    |
151 | /     assert!(
152 | |         same_slice(pg_sys::FMGR_ABI_EXTRA, b"xPostgreSQL\0"),
153 | |         "Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?",
154 | |     );
    | |_____^ the evaluated program panicked at 'Unsupported Postgres ABI. Perhaps you need `--features unsafe-postgres`?', pgrx/src/lib.rs:151:5
    |

贡献

我们绝对欢迎各种类型的贡献。错误报告、功能请求、文档,甚至 赞助

如果您想通过Pull Request提交代码,请将其提交到我们的 develop 分支。现在不再使用 master 分支。

为Postgres内部提供包装不是一个简单的任务,完全包装它需要相当多的时间。pgrx现在通常可以投入使用,并且随着时间的推移将继续开发。我们非常感谢您对如何使用pgrx的反馈。

黑客攻击

如果您正在对pgrx进行黑客攻击并希望确保您的测试可以正确运行,您需要将当前版本的cargo-pgrx(您正在工作的修订版)放入您的PATH

一种简单的方法是安装cargo-local-install

cargo install cargo-local-install

然后运行cargo local-install以安装顶层的Cargo.toml中指定的cargo-pgrx

别忘了将/path/to/pgrx/bin添加到您的PATH前面!

这种方法也可以用于扩展以确保使用与cargo-pgrx匹配的版本。

许可

Portions Copyright 2019-2021 ZomboDB, LLC.  
Portions Copyright 2021-2023 Technology Concepts & Design, Inc.
Portions Copyright 2023 PgCentral Foundation, Inc.

All rights reserved.
Use of this source code is governed by the MIT license that can be found in the LICENSE file.

依赖关系

~5.5–10MB
~178K SLoC