38个版本
| 新版本 0.12.1 | 2024年8月21日 |
|---|---|
| 0.12.0-beta.3 | 2024年7月16日 |
| 0.12.0-alpha.1 | 2024年3月1日 |
| 0.11.2 | 2023年12月5日 |
| 0.10.0-beta.1 | 2023年7月14日 |
在数据库接口中排名第15
每月下载量18,177
用于 8 crates
14MB
367K SLoC

pgrx
用Rust构建Postgres扩展!
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实现扩展
- 许多Rust类型自动映射到PostgreSQL
- 自动生成SQL模式(或通过
cargo pgrx schema手动生成) - 使用
extension_sql!和extension_sql_file!包含自定义 SQL。
- 安全第一
- 将 Rust 的
panic!转换为 Postgres 的ERROR,终止事务而不是进程 - 内存管理遵循 Rust 的 drop 语义,即使在
panic!和elog(ERROR)的情况下也是如此 #[pg_guard]过程宏确保上述功能- Postgres
Datum是Option<T> where T: FromDatumNULLDatum 被安全地表示为Option::<T>::None
- 将 Rust 的
- 支持一等 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工具链:
rustc、cargo和rustfmt。获取这些的推荐方法是来自https://rustup.rs† gitlibclang11或更高版本(用于bindgen)- 类似Debian的系统:
apt install libclang-dev或apt install clang - 类似RHEL的系统:
yum install clang
- 类似Debian的系统:
- 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'
- 类似Debian的系统:
† PGRX没有MSRV策略,因此可能需要Rust的最新稳定版本,可通过Rustup获取
† 不需要本地PostgreSQL服务器安装。使用cargo pgrx可以自行下载和编译PostgreSQL版本。
⹋ PGRX尚未测试在32位上工作:库假设有一个8字节的pg_sys::Datum,这可能导致在32位上的意外行为,例如从int8和double中丢弃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.md的cargo-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]) |
还存在 IntoDatum 和 FromDatum 特性,用于实现额外的类型转换,以及 #[derive(PostgresType)] 和 #[derive(PostgresEnum)] 以自动转换自定义类型。
请注意,text 和 varchar 转换为 &str 或 String,因此 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