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: FromDatum
NULL
Datum 被安全地表示为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† git
libclang
11或更高版本(用于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